summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/network/socket
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qabstractsocket.cpp2920
-rw-r--r--src/network/socket/qabstractsocket.h260
-rw-r--r--src/network/socket/qabstractsocket_p.h169
-rw-r--r--src/network/socket/qabstractsocketengine.cpp268
-rw-r--r--src/network/socket/qabstractsocketengine_p.h235
-rw-r--r--src/network/socket/qhttpsocketengine.cpp824
-rw-r--r--src/network/socket/qhttpsocketengine_p.h199
-rw-r--r--src/network/socket/qlocalserver.cpp401
-rw-r--r--src/network/socket/qlocalserver.h99
-rw-r--r--src/network/socket/qlocalserver_p.h131
-rw-r--r--src/network/socket/qlocalserver_tcp.cpp129
-rw-r--r--src/network/socket/qlocalserver_unix.cpp266
-rw-r--r--src/network/socket/qlocalserver_win.cpp210
-rw-r--r--src/network/socket/qlocalsocket.cpp507
-rw-r--r--src/network/socket/qlocalsocket.h158
-rw-r--r--src/network/socket/qlocalsocket_p.h180
-rw-r--r--src/network/socket/qlocalsocket_tcp.cpp437
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp581
-rw-r--r--src/network/socket/qlocalsocket_win.cpp633
-rw-r--r--src/network/socket/qnativesocketengine.cpp1258
-rw-r--r--src/network/socket/qnativesocketengine_p.h277
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp1125
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp1439
-rw-r--r--src/network/socket/qnet_unix_p.h204
-rw-r--r--src/network/socket/qsocks5socketengine.cpp1923
-rw-r--r--src/network/socket/qsocks5socketengine_p.h299
-rw-r--r--src/network/socket/qsymbiansocketengine.cpp1730
-rw-r--r--src/network/socket/qsymbiansocketengine_p.h256
-rw-r--r--src/network/socket/qtcpserver.cpp691
-rw-r--r--src/network/socket/qtcpserver.h110
-rw-r--r--src/network/socket/qtcpsocket.cpp124
-rw-r--r--src/network/socket/qtcpsocket.h75
-rw-r--r--src/network/socket/qtcpsocket_p.h68
-rw-r--r--src/network/socket/qudpsocket.cpp567
-rw-r--r--src/network/socket/qudpsocket.h112
-rw-r--r--src/network/socket/socket.pri70
36 files changed, 18935 insertions, 0 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
new file mode 100644
index 0000000000..7af71ccc8b
--- /dev/null
+++ b/src/network/socket/qabstractsocket.cpp
@@ -0,0 +1,2920 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QABSTRACTSOCKET_DEBUG
+
+/*!
+ \class QAbstractSocket
+
+ \brief The QAbstractSocket class provides the base functionality
+ common to all socket types.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ QAbstractSocket is the base class for QTcpSocket and QUdpSocket
+ and contains all common functionality of these two classes. If
+ you need a socket, you have two options:
+
+ \list
+ \i Instantiate QTcpSocket or QUdpSocket.
+ \i Create a native socket descriptor, instantiate
+ QAbstractSocket, and call setSocketDescriptor() to wrap the
+ native socket.
+ \endlist
+
+ TCP (Transmission Control Protocol) is a reliable,
+ stream-oriented, connection-oriented transport protocol. UDP
+ (User Datagram Protocol) is an unreliable, datagram-oriented,
+ connectionless protocol. In practice, this means that TCP is
+ better suited for continuous transmission of data, whereas the
+ more lightweight UDP can be used when reliability isn't
+ important.
+
+ QAbstractSocket's API unifies most of the differences between the
+ two protocols. For example, although UDP is connectionless,
+ connectToHost() establishes a virtual connection for UDP sockets,
+ enabling you to use QAbstractSocket in more or less the same way
+ regardless of the underlying protocol. Internally,
+ QAbstractSocket remembers the address and port passed to
+ connectToHost(), and functions like read() and write() use these
+ values.
+
+ At any time, QAbstractSocket has a state (returned by
+ state()). The initial state is UnconnectedState. After
+ calling connectToHost(), the socket first enters
+ HostLookupState. If the host is found, QAbstractSocket enters
+ ConnectingState and emits the hostFound() signal. When the
+ connection has been established, it enters ConnectedState and
+ emits connected(). If an error occurs at any stage, error() is
+ emitted. Whenever the state changes, stateChanged() is emitted.
+ For convenience, isValid() returns true if the socket is ready for
+ reading and writing, but note that the socket's state must be
+ ConnectedState before reading and writing can occur.
+
+ Read or write data by calling read() or write(), or use the
+ convenience functions readLine() and readAll(). QAbstractSocket
+ also inherits getChar(), putChar(), and ungetChar() from
+ QIODevice, which work on single bytes. The bytesWritten() signal
+ is emitted when data has been written to the socket (i.e., when
+ the client has read the data). Note that Qt does not limit the
+ write buffer size. You can monitor its size by listening to this
+ signal.
+
+ The readyRead() signal is emitted every time a new chunk of data
+ has arrived. bytesAvailable() then returns the number of bytes
+ that are available for reading. Typically, you would connect the
+ readyRead() signal to a slot and read all available data there.
+ If you don't read all the data at once, the remaining data will
+ still be available later, and any new incoming data will be
+ appended to QAbstractSocket's internal read buffer. To limit the
+ size of the read buffer, call setReadBufferSize().
+
+ To close the socket, call disconnectFromHost(). QAbstractSocket enters
+ QAbstractSocket::ClosingState. After all pending data has been written to
+ the socket, QAbstractSocket actually closes the socket, enters
+ QAbstractSocket::ClosedState, and emits disconnected(). If you want to
+ abort a connection immediately, discarding all pending data, call abort()
+ instead. If the remote host closes the connection, QAbstractSocket will
+ emit error(QAbstractSocket::RemoteHostClosedError), during which the socket
+ state will still be ConnectedState, and then the disconnected() signal
+ will be emitted.
+
+ The port and address of the connected peer is fetched by calling
+ peerPort() and peerAddress(). peerName() returns the host name of
+ the peer, as passed to connectToHost(). localPort() and
+ localAddress() return the port and address of the local socket.
+
+ QAbstractSocket provides a set of functions that suspend the
+ calling thread until certain signals are emitted. These functions
+ can be used to implement blocking sockets:
+
+ \list
+ \o waitForConnected() blocks until a connection has been established.
+
+ \o waitForReadyRead() blocks until new data is available for
+ reading.
+
+ \o waitForBytesWritten() blocks until one payload of data has been
+ written to the socket.
+
+ \o waitForDisconnected() blocks until the connection has closed.
+ \endlist
+
+ We show an example:
+
+ \snippet doc/src/snippets/network/tcpwait.cpp 0
+
+ If \l{QIODevice::}{waitForReadyRead()} returns false, the
+ connection has been closed or an error has occurred.
+
+ Programming with a blocking socket is radically different from
+ programming with a non-blocking socket. A blocking socket doesn't
+ require an event loop and typically leads to simpler code.
+ However, in a GUI application, blocking sockets should only be
+ used in non-GUI threads, to avoid freezing the user interface.
+ See the \l network/fortuneclient and \l network/blockingfortuneclient
+ examples for an overview of both approaches.
+
+ \note We discourage the use of the blocking functions together
+ with signals. One of the two possibilities should be used.
+
+ QAbstractSocket can be used with QTextStream and QDataStream's
+ stream operators (operator<<() and operator>>()). There is one
+ issue to be aware of, though: You must make sure that enough data
+ is available before attempting to read it using operator>>().
+
+ \sa QFtp, QNetworkAccessManager, QTcpServer
+*/
+
+/*!
+ \fn void QAbstractSocket::hostFound()
+
+ This signal is emitted after connectToHost() has been called and
+ the host lookup has succeeded.
+
+ \note Since Qt 4.6.3 QAbstractSocket may emit hostFound()
+ directly from the connectToHost() call since a DNS result could have been
+ cached.
+
+ \sa connected()
+*/
+
+/*!
+ \fn void QAbstractSocket::connected()
+
+ This signal is emitted after connectToHost() has been called and
+ a connection has been successfully established.
+
+ \note On some operating systems the connected() signal may
+ be directly emitted from the connectToHost() call for connections
+ to the localhost.
+
+ \sa connectToHost(), disconnected()
+*/
+
+/*!
+ \fn void QAbstractSocket::disconnected()
+
+ This signal is emitted when the socket has been disconnected.
+
+ \warning If you need to delete the sender() of this signal in a slot connected
+ to it, use the \l{QObject::deleteLater()}{deleteLater()} function.
+
+ \sa connectToHost(), disconnectFromHost(), abort()
+*/
+
+/*!
+ \fn void QAbstractSocket::error(QAbstractSocket::SocketError socketError)
+
+ This signal is emitted after an error occurred. The \a socketError
+ parameter describes the type of error that occurred.
+
+ QAbstractSocket::SocketError is not a registered metatype, so for queued
+ connections, you will have to register it with Q_DECLARE_METATYPE() and
+ qRegisterMetaType().
+
+ \sa error(), errorString(), {Creating Custom Qt Types}
+*/
+
+/*!
+ \fn void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)
+
+ This signal is emitted whenever QAbstractSocket's state changes.
+ The \a socketState parameter is the new state.
+
+ QAbstractSocket::SocketState is not a registered metatype, so for queued
+ connections, you will have to register it with Q_REGISTER_METATYPE() and
+ qRegisterMetaType().
+
+ \sa state(), {Creating Custom Qt Types}
+*/
+
+/*!
+ \fn void QAbstractSocket::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
+ \since 4.3
+
+ This signal can be emitted when a \a proxy that requires
+ authentication is used. The \a authenticator object can then be
+ filled in with the required details to allow authentication and
+ continue the connection.
+
+ \note It is not possible to use a QueuedConnection to connect to
+ this signal, as the connection will fail if the authenticator has
+ not been filled in with new information when the signal returns.
+
+ \sa QAuthenticator, QNetworkProxy
+*/
+
+/*!
+ \enum QAbstractSocket::NetworkLayerProtocol
+
+ This enum describes the network layer protocol values used in Qt.
+
+ \value IPv4Protocol IPv4
+ \value IPv6Protocol IPv6
+ \value UnknownNetworkLayerProtocol Other than IPv4 and IPv6
+
+ \sa QHostAddress::protocol()
+*/
+
+/*!
+ \enum QAbstractSocket::SocketType
+
+ This enum describes the transport layer protocol.
+
+ \value TcpSocket TCP
+ \value UdpSocket UDP
+ \value UnknownSocketType Other than TCP and UDP
+
+ \sa QAbstractSocket::socketType()
+*/
+
+/*!
+ \enum QAbstractSocket::SocketError
+
+ This enum describes the socket errors that can occur.
+
+ \value ConnectionRefusedError The connection was refused by the
+ peer (or timed out).
+ \value RemoteHostClosedError The remote host closed the
+ connection. Note that the client socket (i.e., this socket)
+ will be closed after the remote close notification has
+ been sent.
+ \value HostNotFoundError The host address was not found.
+ \value SocketAccessError The socket operation failed because the
+ application lacked the required privileges.
+ \value SocketResourceError The local system ran out of resources
+ (e.g., too many sockets).
+ \value SocketTimeoutError The socket operation timed out.
+ \value DatagramTooLargeError The datagram was larger than the
+ operating system's limit (which can be as low as 8192
+ bytes).
+ \value NetworkError An error occurred with the network (e.g., the
+ network cable was accidentally plugged out).
+ \value AddressInUseError The address specified to QUdpSocket::bind() is
+ already in use and was set to be exclusive.
+ \value SocketAddressNotAvailableError The address specified to
+ QUdpSocket::bind() does not belong to the host.
+ \value UnsupportedSocketOperationError The requested socket operation is
+ not supported by the local operating system (e.g., lack of
+ IPv6 support).
+ \value ProxyAuthenticationRequiredError The socket is using a proxy, and
+ the proxy requires authentication.
+ \value SslHandshakeFailedError The SSL/TLS handshake failed, so
+ the connection was closed (only used in QSslSocket)
+ \value UnfinishedSocketOperationError Used by QAbstractSocketEngine only,
+ The last operation attempted has not finished yet (still in progress in
+ the background).
+ \value ProxyConnectionRefusedError Could not contact the proxy server because
+ the connection to that server was denied
+ \value ProxyConnectionClosedError The connection to the proxy server was closed
+ unexpectedly (before the connection to the final peer was established)
+ \value ProxyConnectionTimeoutError The connection to the proxy server timed out
+ or the proxy server stopped responding in the authentication phase.
+ \value ProxyNotFoundError The proxy address set with setProxy() (or the application
+ proxy) was not found.
+ \value ProxyProtocolError The connection negotiation with the proxy server
+ because the response from the proxy server could not be understood.
+
+ \value UnknownSocketError An unidentified error occurred.
+ \sa QAbstractSocket::error()
+*/
+
+/*!
+ \enum QAbstractSocket::SocketState
+
+ This enum describes the different states in which a socket can be.
+
+ \value UnconnectedState The socket is not connected.
+ \value HostLookupState The socket is performing a host name lookup.
+ \value ConnectingState The socket has started establishing a connection.
+ \value ConnectedState A connection is established.
+ \value BoundState The socket is bound to an address and port (for servers).
+ \value ClosingState The socket is about to close (data may still
+ be waiting to be written).
+ \value ListeningState For internal use only.
+ \omitvalue Idle
+ \omitvalue HostLookup
+ \omitvalue Connecting
+ \omitvalue Connected
+ \omitvalue Closing
+ \omitvalue Connection
+
+ \sa QAbstractSocket::state()
+*/
+
+/*!
+ \enum QAbstractSocket::SocketOption
+ \since 4.6
+
+ This enum represents the options that can be set on a socket.
+ If desired, they can be set after having received the connected() signal from
+ the socket or after having received a new socket from a QTcpServer.
+
+ \value LowDelayOption Try to optimize the socket for low latency. For a QTcpSocket
+ this would set the TCP_NODELAY option and disable Nagle's algorithm. Set this to 1
+ to enable.
+ \value KeepAliveOption Set this to 1 to enable the SO_KEEPALIVE socket option
+
+ \value MulticastTtlOption Set this to an integer value to set IP_MULTICAST_TTL (TTL for multicast datagrams) socket option.
+
+ \value MulticastLoopbackOption Set this to 1 to enable the IP_MULTICAST_LOOP (multicast loopback) socket option.
+
+ \sa QAbstractSocket::setSocketOption(), QAbstractSocket::socketOption()
+*/
+
+#include "qabstractsocket.h"
+#include "qabstractsocket_p.h"
+
+#include "private/qhostinfo_p.h"
+#include "private/qnetworksession_p.h"
+
+#include <qabstracteventdispatcher.h>
+#include <qhostaddress.h>
+#include <qhostinfo.h>
+#include <qmetaobject.h>
+#include <qpointer.h>
+#include <qtimer.h>
+#include <qelapsedtimer.h>
+#include <qscopedvaluerollback.h>
+
+#ifndef QT_NO_OPENSSL
+#include <QtNetwork/qsslsocket.h>
+#endif
+
+#include <private/qthread_p.h>
+
+#ifdef QABSTRACTSOCKET_DEBUG
+#include <qdebug.h>
+#endif
+
+#include <time.h>
+
+#define Q_CHECK_SOCKETENGINE(returnValue) do { \
+ if (!d->socketEngine) { \
+ return returnValue; \
+ } } while (0)
+
+#ifndef QABSTRACTSOCKET_BUFFERSIZE
+#define QABSTRACTSOCKET_BUFFERSIZE 32768
+#endif
+#define QT_CONNECT_TIMEOUT 30000
+#define QT_TRANSFER_TIMEOUT 120000
+
+QT_BEGIN_NAMESPACE
+
+#if defined QABSTRACTSOCKET_DEBUG
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qstring.h>
+#include <ctype.h>
+QT_END_INCLUDE_NAMESPACE
+
+/*
+ Returns a human readable representation of the first \a len
+ characters in \a data.
+*/
+static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
+{
+ if (!data) return "(null)";
+ QByteArray out;
+ for (int i = 0; i < len; ++i) {
+ char c = data[i];
+ if (isprint(int(uchar(c)))) {
+ out += c;
+ } else switch (c) {
+ case '\n': out += "\\n"; break;
+ case '\r': out += "\\r"; break;
+ case '\t': out += "\\t"; break;
+ default:
+ QString tmp;
+ tmp.sprintf("\\%o", c);
+ out += tmp.toLatin1();
+ }
+ }
+
+ if (len < maxLength)
+ out += "...";
+
+ return out;
+}
+#endif
+
+static bool isProxyError(QAbstractSocket::SocketError error)
+{
+ switch (error) {
+ case QAbstractSocket::ProxyAuthenticationRequiredError:
+ case QAbstractSocket::ProxyConnectionRefusedError:
+ case QAbstractSocket::ProxyConnectionClosedError:
+ case QAbstractSocket::ProxyConnectionTimeoutError:
+ case QAbstractSocket::ProxyNotFoundError:
+ case QAbstractSocket::ProxyProtocolError:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*! \internal
+
+ Constructs a QAbstractSocketPrivate. Initializes all members.
+*/
+QAbstractSocketPrivate::QAbstractSocketPrivate()
+ : readSocketNotifierCalled(false),
+ readSocketNotifierState(false),
+ readSocketNotifierStateSet(false),
+ emittedReadyRead(false),
+ emittedBytesWritten(false),
+ abortCalled(false),
+ closeCalled(false),
+ pendingClose(false),
+ port(0),
+ localPort(0),
+ peerPort(0),
+ socketEngine(0),
+ cachedSocketDescriptor(-1),
+ readBufferMaxSize(0),
+ readBuffer(QABSTRACTSOCKET_BUFFERSIZE),
+ writeBuffer(QABSTRACTSOCKET_BUFFERSIZE),
+ isBuffered(false),
+ blockingTimeout(30000),
+ connectTimer(0),
+ disconnectTimer(0),
+ connectTimeElapsed(0),
+ hostLookupId(-1),
+ socketType(QAbstractSocket::UnknownSocketType),
+ state(QAbstractSocket::UnconnectedState),
+ socketError(QAbstractSocket::UnknownSocketError)
+{
+}
+
+/*! \internal
+
+ Destructs the QAbstractSocket. If the socket layer is open, it
+ will be reset.
+*/
+QAbstractSocketPrivate::~QAbstractSocketPrivate()
+{
+}
+
+/*! \internal
+
+ Resets the socket layer, clears the read and write buffers and
+ deletes any socket notifiers.
+*/
+void QAbstractSocketPrivate::resetSocketLayer()
+{
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::resetSocketLayer()");
+#endif
+
+ if (socketEngine) {
+ socketEngine->close();
+ socketEngine->disconnect();
+ delete socketEngine;
+ socketEngine = 0;
+ cachedSocketDescriptor = -1;
+ }
+ if (connectTimer)
+ connectTimer->stop();
+ if (disconnectTimer)
+ disconnectTimer->stop();
+}
+
+/*! \internal
+
+ Initializes the socket layer to by of type \a type, using the
+ network layer protocol \a protocol. Resets the socket layer first
+ if it's already initialized. Sets up the socket notifiers.
+*/
+bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtocol protocol)
+{
+#ifdef QT_NO_NETWORKPROXY
+ // this is here to avoid a duplication of the call to createSocketEngine below
+ static const QNetworkProxy &proxyInUse = *(QNetworkProxy *)0;
+#endif
+
+ Q_Q(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ QString typeStr;
+ if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
+ else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
+ else typeStr = QLatin1String("UnknownSocketType");
+ QString protocolStr;
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
+ else protocolStr = QLatin1String("UnknownNetworkLayerProtocol");
+#endif
+
+ resetSocketLayer();
+ socketEngine = QAbstractSocketEngine::createSocketEngine(q->socketType(), proxyInUse, q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ socketEngine->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
+ if (!socketEngine) {
+ socketError = QAbstractSocket::UnsupportedSocketOperationError;
+ q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
+ return false;
+ }
+ if (!socketEngine->initialize(q->socketType(), protocol)) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::initSocketLayer(%s, %s) failed (%s)",
+ typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(),
+ socketEngine->errorString().toLatin1().constData());
+#endif
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ return false;
+ }
+
+ if (threadData->eventDispatcher)
+ socketEngine->setReceiver(this);
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::initSocketLayer(%s, %s) success",
+ typeStr.toLatin1().constData(), protocolStr.toLatin1().constData());
+#endif
+ return true;
+}
+
+/*! \internal
+
+ Slot connected to the read socket notifier. This slot is called
+ when new data is available for reading, or when the socket has
+ been closed. Handles recursive calls.
+*/
+bool QAbstractSocketPrivate::canReadNotification()
+{
+ Q_Q(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::canReadNotification()");
+#endif
+
+ // Prevent recursive calls
+ if (readSocketNotifierCalled) {
+ if (!readSocketNotifierStateSet) {
+ readSocketNotifierStateSet = true;
+ readSocketNotifierState = socketEngine->isReadNotificationEnabled();
+ socketEngine->setReadNotificationEnabled(false);
+ }
+ }
+ QScopedValueRollback<bool> rsncrollback(readSocketNotifierCalled);
+ readSocketNotifierCalled = true;
+
+ if (!isBuffered)
+ socketEngine->setReadNotificationEnabled(false);
+
+ // If buffered, read data from the socket into the read buffer
+ qint64 newBytes = 0;
+ if (isBuffered) {
+ // Return if there is no space in the buffer
+ if (readBufferMaxSize && readBuffer.size() >= readBufferMaxSize) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full");
+#endif
+ return false;
+ }
+
+ // If reading from the socket fails after getting a read
+ // notification, close the socket.
+ newBytes = readBuffer.size();
+ if (!readFromSocket()) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::canReadNotification() disconnecting socket");
+#endif
+ q->disconnectFromHost();
+ return false;
+ }
+ newBytes = readBuffer.size() - newBytes;
+
+ // If read buffer is full, disable the read socket notifier.
+ if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize) {
+ socketEngine->setReadNotificationEnabled(false);
+ }
+ }
+
+ // only emit readyRead() when not recursing, and only if there is data available
+ bool hasData = newBytes > 0
+#ifndef QT_NO_UDPSOCKET
+ || (!isBuffered && socketType != QAbstractSocket::TcpSocket && socketEngine && socketEngine->hasPendingDatagrams())
+#endif
+ || (!isBuffered && socketType == QAbstractSocket::TcpSocket && socketEngine)
+ ;
+
+ if (!emittedReadyRead && hasData) {
+ QScopedValueRollback<bool> r(emittedReadyRead);
+ emittedReadyRead = true;
+ emit q->readyRead();
+ }
+
+ // If we were closed as a result of the readyRead() signal,
+ // return.
+ if (state == QAbstractSocket::UnconnectedState || state == QAbstractSocket::ClosingState) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::canReadNotification() socket is closing - returning");
+#endif
+ return true;
+ }
+
+ if (!hasData && socketEngine)
+ socketEngine->setReadNotificationEnabled(true);
+
+ // reset the read socket notifier state if we reentered inside the
+ // readyRead() connected slot.
+ if (readSocketNotifierStateSet && socketEngine &&
+ readSocketNotifierState != socketEngine->isReadNotificationEnabled()) {
+ socketEngine->setReadNotificationEnabled(readSocketNotifierState);
+ readSocketNotifierStateSet = false;
+ }
+ return true;
+}
+
+/*! \internal
+
+ Slot connected to the write socket notifier. It's called during a
+ delayed connect or when the socket is ready for writing.
+*/
+bool QAbstractSocketPrivate::canWriteNotification()
+{
+#if defined (Q_OS_WIN)
+ if (socketEngine && socketEngine->isWriteNotificationEnabled())
+ socketEngine->setWriteNotificationEnabled(false);
+#endif
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::canWriteNotification() flushing");
+#endif
+ int tmp = writeBuffer.size();
+ flush();
+
+ if (socketEngine) {
+#if defined (Q_OS_WIN)
+ if (!writeBuffer.isEmpty())
+ socketEngine->setWriteNotificationEnabled(true);
+#else
+ if (writeBuffer.isEmpty() && socketEngine->bytesToWrite() == 0)
+ socketEngine->setWriteNotificationEnabled(false);
+#endif
+ }
+
+ return (writeBuffer.size() < tmp);
+}
+
+/*! \internal
+
+ Slot connected to a notification of connection status
+ change. Either we finished connecting or we failed to connect.
+*/
+void QAbstractSocketPrivate::connectionNotification()
+{
+ // If in connecting state, check if the connection has been
+ // established, otherwise flush pending data.
+ if (state == QAbstractSocket::ConnectingState) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::connectionNotification() testing connection");
+#endif
+ _q_testConnection();
+ }
+}
+
+/*! \internal
+
+ Writes pending data in the write buffers to the socket. The
+ function writes as much as it can without blocking.
+
+ It is usually invoked by canWriteNotification after one or more
+ calls to write().
+
+ Emits bytesWritten().
+*/
+bool QAbstractSocketPrivate::flush()
+{
+ Q_Q(QAbstractSocket);
+ if (!socketEngine || !socketEngine->isValid() || (writeBuffer.isEmpty()
+ && socketEngine->bytesToWrite() == 0)) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::flush() nothing to do: valid ? %s, writeBuffer.isEmpty() ? %s",
+ socketEngine->isValid() ? "yes" : "no", writeBuffer.isEmpty() ? "yes" : "no");
+#endif
+
+ // this covers the case when the buffer was empty, but we had to wait for the socket engine to finish
+ if (state == QAbstractSocket::ClosingState)
+ q->disconnectFromHost();
+
+ return false;
+ }
+
+ int nextSize = writeBuffer.nextDataBlockSize();
+ const char *ptr = writeBuffer.readPointer();
+
+ // Attempt to write it all in one chunk.
+ qint64 written = socketEngine->write(ptr, nextSize);
+ if (written < 0) {
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug() << "QAbstractSocketPrivate::flush() write error, aborting." << socketEngine->errorString();
+#endif
+ emit q->error(socketError);
+ // an unexpected error so close the socket.
+ q->abort();
+ return false;
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::flush() %lld bytes written to the network",
+ written);
+#endif
+
+ // Remove what we wrote so far.
+ writeBuffer.free(written);
+ if (written > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ QScopedValueRollback<bool> r(emittedBytesWritten);
+ emittedBytesWritten = true;
+ emit q->bytesWritten(written);
+ }
+ }
+
+ if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled()
+ && !socketEngine->bytesToWrite())
+ socketEngine->setWriteNotificationEnabled(false);
+ if (state == QAbstractSocket::ClosingState)
+ q->disconnectFromHost();
+
+ return true;
+}
+
+#ifndef QT_NO_NETWORKPROXY
+/*! \internal
+
+ Resolve the proxy to its final value.
+*/
+void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
+{
+ QHostAddress parsed;
+ if (hostname == QLatin1String("localhost")
+ || hostname.startsWith(QLatin1String("localhost."))
+ || (parsed.setAddress(hostname)
+ && (parsed == QHostAddress::LocalHost
+ || parsed == QHostAddress::LocalHostIPv6))) {
+ proxyInUse = QNetworkProxy::NoProxy;
+ return;
+ }
+
+ QList<QNetworkProxy> proxies;
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy) {
+ // a non-default proxy was set with setProxy
+ proxies << proxy;
+ } else {
+ // try the application settings instead
+ QNetworkProxyQuery query(hostname, port, QString(),
+ socketType == QAbstractSocket::TcpSocket ?
+ QNetworkProxyQuery::TcpSocket :
+ QNetworkProxyQuery::UdpSocket);
+ proxies = QNetworkProxyFactory::proxyForQuery(query);
+ }
+
+ // return the first that we can use
+ foreach (const QNetworkProxy &p, proxies) {
+ if (socketType == QAbstractSocket::UdpSocket &&
+ (p.capabilities() & QNetworkProxy::UdpTunnelingCapability) == 0)
+ continue;
+
+ if (socketType == QAbstractSocket::TcpSocket &&
+ (p.capabilities() & QNetworkProxy::TunnelingCapability) == 0)
+ continue;
+
+ proxyInUse = p;
+ return;
+ }
+
+ // no proxy found
+ // DefaultProxy here will raise an error
+ proxyInUse = QNetworkProxy();
+}
+
+/*!
+ \internal
+
+ Starts the connection to \a host, like _q_startConnecting below,
+ but without hostname resolution.
+*/
+void QAbstractSocketPrivate::startConnectingByName(const QString &host)
+{
+ Q_Q(QAbstractSocket);
+ if (state == QAbstractSocket::ConnectingState || state == QAbstractSocket::ConnectedState)
+ return;
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::startConnectingByName(host == %s)", qPrintable(host));
+#endif
+
+ // ### Let the socket engine drive this?
+ state = QAbstractSocket::ConnectingState;
+ emit q->stateChanged(state);
+
+ connectTimeElapsed = 0;
+
+ if (initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) {
+ if (socketEngine->connectToHostByName(host, port) ||
+ socketEngine->state() == QAbstractSocket::ConnectingState) {
+ cachedSocketDescriptor = socketEngine->socketDescriptor();
+
+ return;
+ }
+
+ // failed to connect
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ }
+
+ state = QAbstractSocket::UnconnectedState;
+ emit q->error(socketError);
+ emit q->stateChanged(state);
+}
+
+#endif
+
+/*! \internal
+
+ Slot connected to QHostInfo::lookupHost() in connectToHost(). This
+ function starts the process of connecting to any number of
+ candidate IP addresses for the host, if it was found. Calls
+ _q_connectToNextAddress().
+*/
+void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
+{
+ Q_Q(QAbstractSocket);
+ if (state != QAbstractSocket::HostLookupState)
+ return;
+
+ if (hostLookupId != -1 && hostLookupId != hostInfo.lookupId()) {
+ qWarning("QAbstractSocketPrivate::_q_startConnecting() received hostInfo for wrong lookup ID %d expected %d", hostInfo.lookupId(), hostLookupId);
+ }
+
+ addresses = hostInfo.addresses();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ QString s = QLatin1String("{");
+ for (int i = 0; i < addresses.count(); ++i) {
+ if (i != 0) s += QLatin1String(", ");
+ s += addresses.at(i).toString();
+ }
+ s += QLatin1Char('}');
+ qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData());
+#endif
+
+ // Try all addresses twice.
+ addresses += addresses;
+
+ // If there are no addresses in the host list, report this to the
+ // user.
+ if (addresses.isEmpty()) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_startConnecting(), host not found");
+#endif
+ state = QAbstractSocket::UnconnectedState;
+ socketError = QAbstractSocket::HostNotFoundError;
+ q->setErrorString(QAbstractSocket::tr("Host not found"));
+ emit q->stateChanged(state);
+ emit q->error(QAbstractSocket::HostNotFoundError);
+ return;
+ }
+
+ // Enter Connecting state (see also sn_write, which is called by
+ // the write socket notifier after connect())
+ state = QAbstractSocket::ConnectingState;
+ emit q->stateChanged(state);
+
+ // Report the successful host lookup
+ emit q->hostFound();
+
+ // Reset the total time spent connecting.
+ connectTimeElapsed = 0;
+
+ // The addresses returned by the lookup will be tested one after
+ // another by _q_connectToNextAddress().
+ _q_connectToNextAddress();
+}
+
+/*! \internal
+
+ Called by a queued or direct connection from _q_startConnecting() or
+ _q_testConnection(), this function takes the first address of the
+ pending addresses list and tries to connect to it. If the
+ connection succeeds, QAbstractSocket will emit
+ connected(). Otherwise, error(ConnectionRefusedError) or
+ error(SocketTimeoutError) is emitted.
+*/
+void QAbstractSocketPrivate::_q_connectToNextAddress()
+{
+ Q_Q(QAbstractSocket);
+ do {
+ // Check for more pending addresses
+ if (addresses.isEmpty()) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), all addresses failed.");
+#endif
+ state = QAbstractSocket::UnconnectedState;
+ if (socketEngine) {
+ if ((socketEngine->error() == QAbstractSocket::UnknownSocketError
+#ifdef Q_OS_AIX
+ // On AIX, the second connect call will result in EINVAL and not
+ // ECONNECTIONREFUSED; although the meaning is the same.
+ || socketEngine->error() == QAbstractSocket::UnsupportedSocketOperationError
+#endif
+ ) && socketEngine->state() == QAbstractSocket::ConnectingState) {
+ socketError = QAbstractSocket::ConnectionRefusedError;
+ q->setErrorString(QAbstractSocket::tr("Connection refused"));
+ } else {
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ }
+ } else {
+// socketError = QAbstractSocket::ConnectionRefusedError;
+// q->setErrorString(QAbstractSocket::tr("Connection refused"));
+ }
+ emit q->stateChanged(state);
+ emit q->error(socketError);
+ return;
+ }
+
+ // Pick the first host address candidate
+ host = addresses.takeFirst();
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), connecting to %s:%i, %d left to try",
+ host.toString().toLatin1().constData(), port, addresses.count());
+#endif
+
+#if defined(QT_NO_IPV6)
+ if (host.protocol() == QAbstractSocket::IPv6Protocol) {
+ // If we have no IPv6 support, then we will not be able to
+ // connect. So we just pretend we didn't see this address.
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), skipping IPv6 entry");
+#endif
+ continue;
+ }
+#endif
+
+ if (!initSocketLayer(host.protocol())) {
+ // hope that the next address is better
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), failed to initialize sock layer");
+#endif
+ continue;
+ }
+
+ // Tries to connect to the address. If it succeeds immediately
+ // (localhost address on BSD or any UDP connect), emit
+ // connected() and return.
+ if (socketEngine->connectToHost(host, port)) {
+ //_q_testConnection();
+ fetchConnectionParameters();
+ return;
+ }
+
+ // cache the socket descriptor even if we're not fully connected yet
+ cachedSocketDescriptor = socketEngine->socketDescriptor();
+
+ // Check that we're in delayed connection state. If not, try
+ // the next address
+ if (socketEngine->state() != QAbstractSocket::ConnectingState) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), connection failed (%s)",
+ socketEngine->errorString().toLatin1().constData());
+#endif
+ continue;
+ }
+
+ // Start the connect timer.
+ if (threadData->eventDispatcher) {
+ if (!connectTimer) {
+ connectTimer = new QTimer(q);
+ QObject::connect(connectTimer, SIGNAL(timeout()),
+ q, SLOT(_q_abortConnectionAttempt()),
+ Qt::DirectConnection);
+ }
+ connectTimer->start(QT_CONNECT_TIMEOUT);
+ }
+
+ // Wait for a write notification that will eventually call
+ // _q_testConnection().
+ socketEngine->setWriteNotificationEnabled(true);
+ break;
+ } while (state != QAbstractSocket::ConnectedState);
+}
+
+/*! \internal
+
+ Tests if a connection has been established. If it has, connected()
+ is emitted. Otherwise, _q_connectToNextAddress() is invoked.
+*/
+void QAbstractSocketPrivate::_q_testConnection()
+{
+ if (socketEngine) {
+ if (threadData->eventDispatcher) {
+ if (connectTimer)
+ connectTimer->stop();
+ }
+
+ if (socketEngine->state() == QAbstractSocket::ConnectedState) {
+ // Fetch the parameters if our connection is completed;
+ // otherwise, fall out and try the next address.
+ fetchConnectionParameters();
+ if (pendingClose) {
+ q_func()->disconnectFromHost();
+ pendingClose = false;
+ }
+ return;
+ }
+
+ // don't retry the other addresses if we had a proxy error
+ if (isProxyError(socketEngine->error()))
+ addresses.clear();
+ }
+
+ if (threadData->eventDispatcher) {
+ if (connectTimer)
+ connectTimer->stop();
+ }
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_testConnection() connection failed,"
+ " checking for alternative addresses");
+#endif
+ _q_connectToNextAddress();
+}
+
+/*! \internal
+
+ This function is called after a certain number of seconds has
+ passed while waiting for a connection. It simply tests the
+ connection, and continues to the next address if the connection
+ failed.
+*/
+void QAbstractSocketPrivate::_q_abortConnectionAttempt()
+{
+ Q_Q(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::_q_abortConnectionAttempt() (timed out)");
+#endif
+ if (socketEngine)
+ socketEngine->setWriteNotificationEnabled(false);
+
+ connectTimer->stop();
+
+ if (addresses.isEmpty()) {
+ state = QAbstractSocket::UnconnectedState;
+ socketError = QAbstractSocket::SocketTimeoutError;
+ q->setErrorString(QAbstractSocket::tr("Connection timed out"));
+ emit q->stateChanged(state);
+ emit q->error(socketError);
+ } else {
+ _q_connectToNextAddress();
+ }
+}
+
+void QAbstractSocketPrivate::_q_forceDisconnect()
+{
+ Q_Q(QAbstractSocket);
+ if (socketEngine && socketEngine->isValid() && state == QAbstractSocket::ClosingState) {
+ socketEngine->close();
+ q->disconnectFromHost();
+ }
+}
+
+/*! \internal
+
+ Reads data from the socket layer into the read buffer. Returns
+ true on success; otherwise false.
+*/
+bool QAbstractSocketPrivate::readFromSocket()
+{
+ Q_Q(QAbstractSocket);
+ // Find how many bytes we can read from the socket layer.
+ qint64 bytesToRead = socketEngine->bytesAvailable();
+ if (bytesToRead == 0) {
+ // Under heavy load, certain conditions can trigger read notifications
+ // for socket notifiers on which there is no activity. If we continue
+ // to read 0 bytes from the socket, we will trigger behavior similar
+ // to that which signals a remote close. When we hit this condition,
+ // we try to read 4k of data from the socket, which will give us either
+ // an EAGAIN/EWOULDBLOCK if the connection is alive (i.e., the remote
+ // host has _not_ disappeared).
+ bytesToRead = 4096;
+ }
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size()))
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::readFromSocket() about to read %d bytes",
+ int(bytesToRead));
+#endif
+
+ // Read from the socket, store data in the read buffer.
+ char *ptr = readBuffer.reserve(bytesToRead);
+ qint64 readBytes = socketEngine->read(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ readBuffer.chop(bytesToRead);
+ return true;
+ }
+ readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::readFromSocket() got %d bytes, buffer size = %d",
+ int(readBytes), readBuffer.size());
+#endif
+
+ if (!socketEngine->isValid()) {
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ emit q->error(socketError);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::readFromSocket() read failed: %s",
+ q->errorString().toLatin1().constData());
+#endif
+ resetSocketLayer();
+ return false;
+ }
+
+ return true;
+}
+
+/*! \internal
+
+ Sets up the internal state after the connection has succeeded.
+*/
+void QAbstractSocketPrivate::fetchConnectionParameters()
+{
+ Q_Q(QAbstractSocket);
+
+ peerName = hostName;
+ if (socketEngine) {
+ socketEngine->setReadNotificationEnabled(true);
+ socketEngine->setWriteNotificationEnabled(true);
+ localPort = socketEngine->localPort();
+ peerPort = socketEngine->peerPort();
+ localAddress = socketEngine->localAddress();
+ peerAddress = socketEngine->peerAddress();
+ cachedSocketDescriptor = socketEngine->socketDescriptor();
+ }
+
+ state = QAbstractSocket::ConnectedState;
+ emit q->stateChanged(state);
+ emit q->connected();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::fetchConnectionParameters() connection to %s:%i established",
+ host.toString().toLatin1().constData(), port);
+#endif
+}
+
+
+void QAbstractSocketPrivate::pauseSocketNotifiers(QAbstractSocket *socket)
+{
+ QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine;
+ if (!socketEngine)
+ return;
+ socket->d_func()->prePauseReadSocketNotifierState = socketEngine->isReadNotificationEnabled();
+ socket->d_func()->prePauseWriteSocketNotifierState = socketEngine->isWriteNotificationEnabled();
+ socket->d_func()->prePauseExceptionSocketNotifierState = socketEngine->isExceptionNotificationEnabled();
+ socketEngine->setReadNotificationEnabled(false);
+ socketEngine->setWriteNotificationEnabled(false);
+ socketEngine->setExceptionNotificationEnabled(false);
+}
+
+void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket)
+{
+ QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine;
+ if (!socketEngine)
+ return;
+ socketEngine->setReadNotificationEnabled(socket->d_func()->prePauseReadSocketNotifierState);
+ socketEngine->setWriteNotificationEnabled(socket->d_func()->prePauseWriteSocketNotifierState);
+ socketEngine->setExceptionNotificationEnabled(socket->d_func()->prePauseExceptionSocketNotifierState);
+}
+
+QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket)
+{
+ return socket->d_func()->socketEngine;
+}
+
+
+/*! \internal
+
+ Constructs a new abstract socket of type \a socketType. The \a
+ parent argument is passed to QObject's constructor.
+*/
+QAbstractSocket::QAbstractSocket(SocketType socketType,
+ QAbstractSocketPrivate &dd, QObject *parent)
+ : QIODevice(dd, parent)
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::QAbstractSocket(%sSocket, QAbstractSocketPrivate == %p, parent == %p)",
+ socketType == TcpSocket ? "Tcp" : socketType == UdpSocket
+ ? "Udp" : "Unknown", &dd, parent);
+#endif
+ d->socketType = socketType;
+}
+
+/*!
+ Creates a new abstract socket of type \a socketType. The \a
+ parent argument is passed to QObject's constructor.
+
+ \sa socketType(), QTcpSocket, QUdpSocket
+*/
+QAbstractSocket::QAbstractSocket(SocketType socketType, QObject *parent)
+ : QIODevice(*new QAbstractSocketPrivate, parent)
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::QAbstractSocket(%p)", parent);
+#endif
+ d->socketType = socketType;
+}
+
+/*!
+ Destroys the socket.
+*/
+QAbstractSocket::~QAbstractSocket()
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::~QAbstractSocket()");
+#endif
+ if (d->state != UnconnectedState)
+ abort();
+}
+
+/*!
+ Returns true if the socket is valid and ready for use; otherwise
+ returns false.
+
+ \bold{Note:} The socket's state must be ConnectedState before reading and
+ writing can occur.
+
+ \sa state()
+*/
+bool QAbstractSocket::isValid() const
+{
+ return d_func()->socketEngine ? d_func()->socketEngine->isValid() : isOpen();
+}
+
+/*!
+ Attempts to make a connection to \a hostName on the given \a port.
+
+ The socket is opened in the given \a openMode and first enters
+ HostLookupState, then performs a host name lookup of \a hostName.
+ If the lookup succeeds, hostFound() is emitted and QAbstractSocket
+ enters ConnectingState. It then attempts to connect to the address
+ or addresses returned by the lookup. Finally, if a connection is
+ established, QAbstractSocket enters ConnectedState and
+ emits connected().
+
+ At any point, the socket can emit error() to signal that an error
+ occurred.
+
+ \a hostName may be an IP address in string form (e.g.,
+ "43.195.83.32"), or it may be a host name (e.g.,
+ "example.com"). QAbstractSocket will do a lookup only if
+ required. \a port is in native byte order.
+
+ \sa state(), peerName(), peerAddress(), peerPort(), waitForConnected()
+*/
+void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
+ OpenMode openMode)
+{
+ QMetaObject::invokeMethod(this, "connectToHostImplementation",
+ Qt::DirectConnection,
+ Q_ARG(QString, hostName),
+ Q_ARG(quint16, port),
+ Q_ARG(OpenMode, openMode));
+}
+
+/*!
+ \since 4.1
+
+ Contains the implementation of connectToHost().
+
+ Attempts to make a connection to \a hostName on the given \a
+ port. The socket is opened in the given \a openMode.
+*/
+void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint16 port,
+ OpenMode openMode)
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::connectToHost(\"%s\", %i, %i)...", qPrintable(hostName), port,
+ (int) openMode);
+#endif
+
+ if (d->state == ConnectedState || d->state == ConnectingState
+ || d->state == ClosingState || d->state == HostLookupState) {
+ qWarning("QAbstractSocket::connectToHost() called when already looking up or connecting/connected to \"%s\"", qPrintable(hostName));
+ return;
+ }
+
+ d->hostName = hostName;
+ d->port = port;
+ d->state = UnconnectedState;
+ d->readBuffer.clear();
+ d->writeBuffer.clear();
+ d->abortCalled = false;
+ d->closeCalled = false;
+ d->pendingClose = false;
+ d->localPort = 0;
+ d->peerPort = 0;
+ d->localAddress.clear();
+ d->peerAddress.clear();
+ d->peerName = hostName;
+ if (d->hostLookupId != -1) {
+ QHostInfo::abortHostLookup(d->hostLookupId);
+ d->hostLookupId = -1;
+ }
+
+#ifndef QT_NO_NETWORKPROXY
+ // Get the proxy information
+ d->resolveProxy(hostName, port);
+ if (d->proxyInUse.type() == QNetworkProxy::DefaultProxy) {
+ // failed to setup the proxy
+ d->socketError = QAbstractSocket::UnsupportedSocketOperationError;
+ setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
+ emit error(d->socketError);
+ return;
+ }
+#endif
+
+ if (openMode & QIODevice::Unbuffered)
+ d->isBuffered = false; // Unbuffered QTcpSocket
+ else if (!d_func()->isBuffered)
+ openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
+
+ QIODevice::open(openMode);
+ d->state = HostLookupState;
+ emit stateChanged(d->state);
+
+ QHostAddress temp;
+ if (temp.setAddress(hostName)) {
+ QHostInfo info;
+ info.setAddresses(QList<QHostAddress>() << temp);
+ d->_q_startConnecting(info);
+#ifndef QT_NO_NETWORKPROXY
+ } else if (d->proxyInUse.capabilities() & QNetworkProxy::HostNameLookupCapability) {
+ // the proxy supports connection by name, so use it
+ d->startConnectingByName(hostName);
+ return;
+#endif
+ } else {
+ if (d->threadData->eventDispatcher) {
+ // this internal API for QHostInfo either immediately gives us the desired
+ // QHostInfo from cache or later calls the _q_startConnecting slot.
+ bool immediateResultValid = false;
+ QHostInfo hostInfo = qt_qhostinfo_lookup(hostName,
+ this,
+ SLOT(_q_startConnecting(QHostInfo)),
+ &immediateResultValid,
+ &d->hostLookupId);
+ if (immediateResultValid) {
+ d->hostLookupId = -1;
+ d->_q_startConnecting(hostInfo);
+ }
+ }
+ }
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::connectToHost(\"%s\", %i) == %s%s", hostName.toLatin1().constData(), port,
+ (d->state == ConnectedState) ? "true" : "false",
+ (d->state == ConnectingState || d->state == HostLookupState)
+ ? " (connection in progress)" : "");
+#endif
+}
+
+/*! \overload
+
+ Attempts to make a connection to \a address on port \a port.
+*/
+void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port,
+ OpenMode openMode)
+{
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::connectToHost([%s], %i, %i)...",
+ address.toString().toLatin1().constData(), port, (int) openMode);
+#endif
+ connectToHost(address.toString(), port, openMode);
+}
+
+/*!
+ Returns the number of bytes that are waiting to be written. The
+ bytes are written when control goes back to the event loop or
+ when flush() is called.
+
+ \sa bytesAvailable(), flush()
+*/
+qint64 QAbstractSocket::bytesToWrite() const
+{
+ Q_D(const QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::bytesToWrite() == %i", d->writeBuffer.size());
+#endif
+ return (qint64)d->writeBuffer.size();
+}
+
+/*!
+ Returns the number of incoming bytes that are waiting to be read.
+
+ \sa bytesToWrite(), read()
+*/
+qint64 QAbstractSocket::bytesAvailable() const
+{
+ Q_D(const QAbstractSocket);
+ qint64 available = QIODevice::bytesAvailable();
+
+ available += (qint64) d->readBuffer.size();
+
+ if (!d->isBuffered && d->socketEngine && d->socketEngine->isValid())
+ available += d->socketEngine->bytesAvailable();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::bytesAvailable() == %llu", available);
+#endif
+ return available;
+}
+
+/*!
+ Returns the host port number (in native byte order) of the local
+ socket if available; otherwise returns 0.
+
+ \sa localAddress(), peerPort(), setLocalPort()
+*/
+quint16 QAbstractSocket::localPort() const
+{
+ Q_D(const QAbstractSocket);
+ return d->localPort;
+}
+
+/*!
+ Returns the host address of the local socket if available;
+ otherwise returns QHostAddress::Null.
+
+ This is normally the main IP address of the host, but can be
+ QHostAddress::LocalHost (127.0.0.1) for connections to the
+ local host.
+
+ \sa localPort(), peerAddress(), setLocalAddress()
+*/
+QHostAddress QAbstractSocket::localAddress() const
+{
+ Q_D(const QAbstractSocket);
+ return d->localAddress;
+}
+
+/*!
+ Returns the port of the connected peer if the socket is in
+ ConnectedState; otherwise returns 0.
+
+ \sa peerAddress(), localPort(), setPeerPort()
+*/
+quint16 QAbstractSocket::peerPort() const
+{
+ Q_D(const QAbstractSocket);
+ return d->peerPort;
+}
+
+/*!
+ Returns the address of the connected peer if the socket is in
+ ConnectedState; otherwise returns QHostAddress::Null.
+
+ \sa peerName(), peerPort(), localAddress(), setPeerAddress()
+*/
+QHostAddress QAbstractSocket::peerAddress() const
+{
+ Q_D(const QAbstractSocket);
+ return d->peerAddress;
+}
+
+/*!
+ Returns the name of the peer as specified by connectToHost(), or
+ an empty QString if connectToHost() has not been called.
+
+ \sa peerAddress(), peerPort(), setPeerName()
+*/
+QString QAbstractSocket::peerName() const
+{
+ Q_D(const QAbstractSocket);
+ return d->peerName.isEmpty() ? d->hostName : d->peerName;
+}
+
+/*!
+ Returns true if a line of data can be read from the socket;
+ otherwise returns false.
+
+ \sa readLine()
+*/
+bool QAbstractSocket::canReadLine() const
+{
+ bool hasLine = d_func()->readBuffer.canReadLine();
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::canReadLine() == %s, buffer size = %d, size = %d", hasLine ? "true" : "false",
+ d_func()->readBuffer.size(), d_func()->buffer.size());
+#endif
+ return hasLine || QIODevice::canReadLine();
+}
+
+/*!
+ Returns the native socket descriptor of the QAbstractSocket object
+ if this is available; otherwise returns -1.
+
+ If the socket is using QNetworkProxy, the returned descriptor
+ may not be usable with native socket functions.
+
+ The socket descriptor is not available when QAbstractSocket is in
+ UnconnectedState.
+
+ \sa setSocketDescriptor()
+*/
+int QAbstractSocket::socketDescriptor() const
+{
+ Q_D(const QAbstractSocket);
+ return d->cachedSocketDescriptor;
+}
+
+/*!
+ Initializes QAbstractSocket with the native socket descriptor \a
+ socketDescriptor. Returns true if \a socketDescriptor is accepted
+ as a valid socket descriptor; otherwise returns false.
+ The socket is opened in the mode specified by \a openMode, and
+ enters the socket state specified by \a socketState.
+
+ \bold{Note:} It is not possible to initialize two abstract sockets
+ with the same native socket descriptor.
+
+ \sa socketDescriptor()
+*/
+bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState socketState,
+ OpenMode openMode)
+{
+ Q_D(QAbstractSocket);
+#ifndef QT_NO_OPENSSL
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this))
+ return socket->setSocketDescriptor(socketDescriptor, socketState, openMode);
+#endif
+
+ d->resetSocketLayer();
+ d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this);
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
+ if (!d->socketEngine) {
+ d->socketError = UnsupportedSocketOperationError;
+ setErrorString(tr("Operation on socket is not supported"));
+ return false;
+ }
+ bool result = d->socketEngine->initialize(socketDescriptor, socketState);
+ if (!result) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ return false;
+ }
+
+ if (d->threadData->eventDispatcher)
+ d->socketEngine->setReceiver(d);
+
+ QIODevice::open(openMode);
+
+ if (d->state != socketState) {
+ d->state = socketState;
+ emit stateChanged(d->state);
+ }
+
+ d->pendingClose = false;
+ d->socketEngine->setReadNotificationEnabled(true);
+ d->localPort = d->socketEngine->localPort();
+ d->peerPort = d->socketEngine->peerPort();
+ d->localAddress = d->socketEngine->localAddress();
+ d->peerAddress = d->socketEngine->peerAddress();
+ d->cachedSocketDescriptor = socketDescriptor;
+
+ return true;
+}
+
+/*!
+ \since 4.6
+ Sets the given \a option to the value described by \a value.
+
+ \sa socketOption()
+*/
+void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
+{
+#ifndef QT_NO_OPENSSL
+ if (QSslSocket *sslSocket = qobject_cast<QSslSocket*>(this)) {
+ sslSocket->setSocketOption(option, value);
+ return;
+ }
+#endif
+
+ if (!d_func()->socketEngine)
+ return;
+
+ switch (option) {
+ case LowDelayOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::LowDelayOption, value.toInt());
+ break;
+
+ case KeepAliveOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::KeepAliveOption, value.toInt());
+ break;
+
+ case MulticastTtlOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::MulticastTtlOption, value.toInt());
+ break;
+
+ case MulticastLoopbackOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::MulticastLoopbackOption, value.toInt());
+ break;
+ }
+}
+
+/*!
+ \since 4.6
+ Returns the value of the \a option option.
+
+ \sa setSocketOption()
+*/
+QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option)
+{
+#ifndef QT_NO_OPENSSL
+ if (QSslSocket *sslSocket = qobject_cast<QSslSocket*>(this)) {
+ return sslSocket->socketOption(option);
+ }
+#endif
+
+ if (!d_func()->socketEngine)
+ return QVariant();
+
+ int ret = -1;
+ switch (option) {
+ case LowDelayOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::LowDelayOption);
+ break;
+
+ case KeepAliveOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::KeepAliveOption);
+ break;
+
+ case MulticastTtlOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::MulticastTtlOption);
+ break;
+ case MulticastLoopbackOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::MulticastLoopbackOption);
+ break;
+ }
+ if (ret == -1)
+ return QVariant();
+ else
+ return QVariant(ret);
+}
+
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/*!
+ Waits until the socket is connected, up to \a msecs
+ milliseconds. If the connection has been established, this
+ function returns true; otherwise it returns false. In the case
+ where it returns false, you can call error() to determine
+ the cause of the error.
+
+ The following example waits up to one second for a connection
+ to be established:
+
+ \snippet doc/src/snippets/code/src_network_socket_qabstractsocket.cpp 0
+
+ If msecs is -1, this function will not time out.
+
+ \note This function may wait slightly longer than \a msecs,
+ depending on the time it takes to complete the host lookup.
+
+ \note Multiple calls to this functions do not accumulate the time.
+ If the function times out, the connecting process will be aborted.
+
+ \sa connectToHost(), connected()
+*/
+bool QAbstractSocket::waitForConnected(int msecs)
+{
+ Q_D(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForConnected(%i)", msecs);
+#endif
+
+ if (state() == ConnectedState) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForConnected(%i) already connected", msecs);
+#endif
+ return true;
+ }
+
+#ifndef QT_NO_OPENSSL
+ // Manual polymorphism; this function is not virtual, but has an overload
+ // in QSslSocket.
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this))
+ return socket->waitForConnected(msecs);
+#endif
+
+ bool wasPendingClose = d->pendingClose;
+ d->pendingClose = false;
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ if (d->state == HostLookupState) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForConnected(%i) doing host name lookup", msecs);
+#endif
+ QHostInfo::abortHostLookup(d->hostLookupId);
+ d->hostLookupId = -1;
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession;
+ QVariant v(property("_q_networksession"));
+ if (v.isValid()) {
+ networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(v);
+ d->_q_startConnecting(QHostInfoPrivate::fromName(d->hostName, networkSession));
+ } else
+#endif
+ d->_q_startConnecting(QHostInfo::fromName(d->hostName));
+ }
+ if (state() == UnconnectedState)
+ return false; // connect not im progress anymore!
+
+ bool timedOut = true;
+#if defined (QABSTRACTSOCKET_DEBUG)
+ int attempt = 1;
+#endif
+ while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) {
+ int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
+ if (msecs != -1 && timeout > QT_CONNECT_TIMEOUT)
+ timeout = QT_CONNECT_TIMEOUT;
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
+ msecs, timeout / 1000.0, attempt++);
+#endif
+ timedOut = false;
+
+ if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) {
+ d->_q_testConnection();
+ } else {
+ d->_q_connectToNextAddress();
+ }
+ }
+
+ if ((timedOut && state() != ConnectedState) || state() == ConnectingState) {
+ d->socketError = SocketTimeoutError;
+ d->state = UnconnectedState;
+ emit stateChanged(d->state);
+ d->resetSocketLayer();
+ setErrorString(tr("Socket operation timed out"));
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForConnected(%i) == %s", msecs,
+ state() == ConnectedState ? "true" : "false");
+#endif
+ if (state() != ConnectedState)
+ return false;
+ if (wasPendingClose)
+ disconnectFromHost();
+ return true;
+}
+
+/*!
+ This function blocks until new data is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+
+ \sa waitForBytesWritten()
+*/
+bool QAbstractSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForReadyRead(%i)", msecs);
+#endif
+
+ // require calling connectToHost() before waitForReadyRead()
+ if (state() == UnconnectedState) {
+ /* If all you have is a QIODevice pointer to an abstractsocket, you cannot check
+ this, so you cannot avoid this warning. */
+// qWarning("QAbstractSocket::waitForReadyRead() is not allowed in UnconnectedState");
+ return false;
+ }
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // handle a socket in connecting state
+ if (state() == HostLookupState || state() == ConnectingState) {
+ if (!waitForConnected(msecs))
+ return false;
+ }
+
+ Q_ASSERT(d->socketEngine);
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
+ qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
+ msecs, d->socketError, errorString().toLatin1().constData());
+#endif
+ emit error(d->socketError);
+ if (d->socketError != SocketTimeoutError)
+ close();
+ return false;
+ }
+
+ if (readyToRead) {
+ if (d->canReadNotification())
+ return true;
+ }
+
+ if (readyToWrite)
+ d->canWriteNotification();
+
+ if (state() != ConnectedState)
+ return false;
+ }
+ return false;
+}
+
+/*! \reimp
+ */
+bool QAbstractSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForBytesWritten(%i)", msecs);
+#endif
+
+ // require calling connectToHost() before waitForBytesWritten()
+ if (state() == UnconnectedState) {
+ qWarning("QAbstractSocket::waitForBytesWritten() is not allowed in UnconnectedState");
+ return false;
+ }
+
+ if (d->writeBuffer.isEmpty())
+ return false;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // handle a socket in connecting state
+ if (state() == HostLookupState || state() == ConnectingState) {
+ if (!waitForConnected(msecs))
+ return false;
+ }
+
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
+ qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
+ msecs, d->socketError, errorString().toLatin1().constData());
+#endif
+ emit error(d->socketError);
+ if (d->socketError != SocketTimeoutError)
+ close();
+ return false;
+ }
+
+ if (readyToRead) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForBytesWritten calls canReadNotification");
+#endif
+ if(!d->canReadNotification())
+ return false;
+ }
+
+
+ if (readyToWrite) {
+ if (d->canWriteNotification()) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForBytesWritten returns true");
+#endif
+ return true;
+ }
+ }
+
+ if (state() != ConnectedState)
+ return false;
+ }
+ return false;
+}
+
+/*!
+ Waits until the socket has disconnected, up to \a msecs
+ milliseconds. If the connection has been disconnected, this
+ function returns true; otherwise it returns false. In the case
+ where it returns false, you can call error() to determine
+ the cause of the error.
+
+ The following example waits up to one second for a connection
+ to be closed:
+
+ \snippet doc/src/snippets/code/src_network_socket_qabstractsocket.cpp 1
+
+ If msecs is -1, this function will not time out.
+
+ \sa disconnectFromHost(), close()
+*/
+bool QAbstractSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QAbstractSocket);
+#ifndef QT_NO_OPENSSL
+ // Manual polymorphism; this function is not virtual, but has an overload
+ // in QSslSocket.
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this))
+ return socket->waitForDisconnected(msecs);
+#endif
+
+ // require calling connectToHost() before waitForDisconnected()
+ if (state() == UnconnectedState) {
+ qWarning("QAbstractSocket::waitForDisconnected() is not allowed in UnconnectedState");
+ return false;
+ }
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // handle a socket in connecting state
+ if (state() == HostLookupState || state() == ConnectingState) {
+ if (!waitForConnected(msecs))
+ return false;
+ if (state() == UnconnectedState)
+ return true;
+ }
+
+ forever {
+ bool readyToRead = false;
+ bool readyToWrite = false;
+ if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
+ !d->writeBuffer.isEmpty(),
+ qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
+ msecs, d->socketError, errorString().toLatin1().constData());
+#endif
+ emit error(d->socketError);
+ if (d->socketError != SocketTimeoutError)
+ close();
+ return false;
+ }
+
+ if (readyToRead)
+ d->canReadNotification();
+ if (readyToWrite)
+ d->canWriteNotification();
+
+ if (state() == UnconnectedState)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Aborts the current connection and resets the socket. Unlike disconnectFromHost(),
+ this function immediately closes the socket, discarding any pending data in the
+ write buffer.
+
+ \sa disconnectFromHost(), close()
+*/
+void QAbstractSocket::abort()
+{
+ Q_D(QAbstractSocket);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::abort()");
+#endif
+ if (d->state == UnconnectedState)
+ return;
+#ifndef QT_NO_OPENSSL
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this)) {
+ socket->abort();
+ return;
+ }
+#endif
+ if (d->connectTimer) {
+ d->connectTimer->stop();
+ delete d->connectTimer;
+ d->connectTimer = 0;
+ }
+
+ d->writeBuffer.clear();
+ d->abortCalled = true;
+ close();
+}
+
+/*! \reimp
+*/
+bool QAbstractSocket::isSequential() const
+{
+ return true;
+}
+
+/*! \reimp
+
+ Returns true if no more data is currently
+ available for reading; otherwise returns false.
+
+ This function is most commonly used when reading data from the
+ socket in a loop. For example:
+
+ \snippet doc/src/snippets/code/src_network_socket_qabstractsocket.cpp 2
+
+ \sa bytesAvailable(), readyRead()
+ */
+bool QAbstractSocket::atEnd() const
+{
+ return QIODevice::atEnd() && (!isOpen() || d_func()->readBuffer.isEmpty());
+}
+
+/*!
+ This function writes as much as possible from the internal write buffer to
+ the underlying network socket, without blocking. If any data was written,
+ this function returns true; otherwise false is returned.
+
+ Call this function if you need QAbstractSocket to start sending buffered
+ data immediately. The number of bytes successfully written depends on the
+ operating system. In most cases, you do not need to call this function,
+ because QAbstractSocket will start sending data automatically once control
+ goes back to the event loop. In the absence of an event loop, call
+ waitForBytesWritten() instead.
+
+ \sa write(), waitForBytesWritten()
+*/
+// Note! docs copied to QSslSocket::flush()
+bool QAbstractSocket::flush()
+{
+ Q_D(QAbstractSocket);
+#ifndef QT_NO_OPENSSL
+ // Manual polymorphism; flush() isn't virtual, but QSslSocket overloads
+ // it.
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this))
+ return socket->flush();
+#endif
+ Q_CHECK_SOCKETENGINE(false);
+ return d->flush();
+}
+
+/*! \reimp
+*/
+qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
+{
+ Q_D(QAbstractSocket);
+
+ // This is for a buffered QTcpSocket
+ if (d->isBuffered && d->readBuffer.isEmpty())
+ // if we're still connected, return 0 indicating there may be more data in the future
+ // if we're not connected, return -1 indicating EOF
+ return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1);
+
+ // short cut for a char read if we have something in the buffer
+ if (maxSize == 1 && !d->readBuffer.isEmpty()) {
+ *data = d->readBuffer.getChar();
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1 [char buffer]",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data);
+#endif
+ if (d->readBuffer.isEmpty() && d->socketEngine && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+ return 1;
+ }
+
+ // Special case for an Unbuffered QTcpSocket
+ // Re-filling the buffer.
+ if (d->socketType == TcpSocket
+ && !d->isBuffered
+ && d->readBuffer.size() < maxSize
+ && d->readBufferMaxSize > 0
+ && maxSize < d->readBufferMaxSize
+ && d->socketEngine
+ && d->socketEngine->isValid()) {
+ // Our buffer is empty and a read() was requested for a byte amount that is smaller
+ // than the readBufferMaxSize. This means that we should fill our buffer since we want
+ // such small reads come from the buffer and not always go to the costly socket engine read()
+ qint64 bytesToRead = d->socketEngine->bytesAvailable();
+ if (bytesToRead > 0) {
+ char *ptr = d->readBuffer.reserve(bytesToRead);
+ qint64 readBytes = d->socketEngine->read(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ d->readBuffer.chop(bytesToRead);
+ } else {
+ d->readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+ }
+ }
+ }
+
+ // First try to satisfy the read from the buffer
+ qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);
+ qint64 readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = d->readBuffer.readPointer();
+ int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
+ d->readBuffer.nextDataBlockSize());
+ memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ d->readBuffer.free(bytesToReadFromThisBlock);
+ }
+
+ if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ if (readSoFar > 0) {
+ // we read some data from buffer.
+ // Just return, readyRead will be emitted again
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', %lli) == %lli [buffer]",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data, maxSize, readSoFar);
+#endif
+
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
+ return readSoFar;
+ }
+
+ // This code path is for Unbuffered QTcpSocket or for connected UDP
+
+ if (!d->isBuffered) {
+ if (!d->socketEngine)
+ return -1; // no socket engine is probably EOF
+ if (!d->socketEngine->isValid())
+ return -1; // This is for unbuffered TCP when we already had been disconnected
+ if (d->state != QAbstractSocket::ConnectedState)
+ return -1; // This is for unbuffered TCP if we're not connected yet
+ qint64 readBytes = d->socketEngine->read(data, maxSize);
+ if (readBytes == -2) {
+ // -2 from the engine means no bytes available (EAGAIN) so read more later
+ return 0;
+ } else if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ d->resetSocketLayer();
+ d->state = QAbstractSocket::UnconnectedState;
+ } else if (!d->socketEngine->isReadNotificationEnabled()) {
+ // Only do this when there was no error
+ d->socketEngine->setReadNotificationEnabled(true);
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]",
+ data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
+ readBytes);
+#endif
+ return readBytes;
+ }
+
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [unreachable]",
+ data, qt_prettyDebug(data, qMin<qint64>(32, readSoFar), readSoFar).data(),
+ maxSize, readSoFar);
+#endif
+ return readSoFar;
+}
+
+/*! \reimp
+*/
+qint64 QAbstractSocket::readLineData(char *data, qint64 maxlen)
+{
+ return QIODevice::readLineData(data, maxlen);
+}
+
+/*! \reimp
+*/
+qint64 QAbstractSocket::writeData(const char *data, qint64 size)
+{
+ Q_D(QAbstractSocket);
+ if (d->state == QAbstractSocket::UnconnectedState) {
+ d->socketError = QAbstractSocket::UnknownSocketError;
+ setErrorString(tr("Socket is not connected"));
+ return -1;
+ }
+
+ if (!d->isBuffered && d->socketType == TcpSocket && d->writeBuffer.isEmpty()) {
+ // This code is for the new Unbuffered QTcpSocket use case
+ qint64 written = d->socketEngine->write(data, size);
+ if (written < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ return written;
+ } else if (written < size) {
+ // Buffer what was not written yet
+ char *ptr = d->writeBuffer.reserve(size - written);
+ memcpy(ptr, data + written, size - written);
+ if (d->socketEngine)
+ d->socketEngine->setWriteNotificationEnabled(true);
+ }
+ return size; // size=actually written + what has been buffered
+ } else if (!d->isBuffered && d->socketType != TcpSocket) {
+ // This is for a QUdpSocket that was connect()ed
+ qint64 written = d->socketEngine->write(data, size);
+ if (written < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ } else if (!d->writeBuffer.isEmpty()) {
+ d->socketEngine->setWriteNotificationEnabled(true);
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data,
+ qt_prettyDebug(data, qMin((int)size, 32), size).data(),
+ size, written);
+#endif
+ if (written >= 0)
+ emit bytesWritten(written);
+ return written;
+ }
+
+ // This is the code path for normal buffered QTcpSocket or
+ // unbuffered QTcpSocket when there was already something in the
+ // write buffer and therefore we could not do a direct engine write.
+ // We just write to our write buffer and enable the write notifier
+ // The write notifier then flush()es the buffer.
+
+ char *ptr = d->writeBuffer.reserve(size);
+ if (size == 1)
+ *ptr = *data;
+ else
+ memcpy(ptr, data, size);
+
+ qint64 written = size;
+
+ if (d->socketEngine && !d->writeBuffer.isEmpty())
+ d->socketEngine->setWriteNotificationEnabled(true);
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data,
+ qt_prettyDebug(data, qMin((int)size, 32), size).data(),
+ size, written);
+#endif
+ return written;
+}
+
+/*!
+ \since 4.1
+
+ Sets the port on the local side of a connection to \a port.
+
+ You can call this function in a subclass of QAbstractSocket to
+ change the return value of the localPort() function after a
+ connection has been established. This feature is commonly used by
+ proxy connections for virtual connection settings.
+
+ Note that this function does not bind the local port of the socket
+ prior to a connection (e.g., QUdpSocket::bind()).
+
+ \sa localAddress(), setLocalAddress(), setPeerPort()
+*/
+void QAbstractSocket::setLocalPort(quint16 port)
+{
+ Q_D(QAbstractSocket);
+ d->localPort = port;
+}
+
+/*!
+ \since 4.1
+
+ Sets the address on the local side of a connection to
+ \a address.
+
+ You can call this function in a subclass of QAbstractSocket to
+ change the return value of the localAddress() function after a
+ connection has been established. This feature is commonly used by
+ proxy connections for virtual connection settings.
+
+ Note that this function does not bind the local address of the socket
+ prior to a connection (e.g., QUdpSocket::bind()).
+
+ \sa localAddress(), setLocalPort(), setPeerAddress()
+*/
+void QAbstractSocket::setLocalAddress(const QHostAddress &address)
+{
+ Q_D(QAbstractSocket);
+ d->localAddress = address;
+}
+
+/*!
+ \since 4.1
+
+ Sets the port of the remote side of the connection to
+ \a port.
+
+ You can call this function in a subclass of QAbstractSocket to
+ change the return value of the peerPort() function after a
+ connection has been established. This feature is commonly used by
+ proxy connections for virtual connection settings.
+
+ \sa peerPort(), setPeerAddress(), setLocalPort()
+*/
+void QAbstractSocket::setPeerPort(quint16 port)
+{
+ Q_D(QAbstractSocket);
+ d->peerPort = port;
+}
+
+/*!
+ \since 4.1
+
+ Sets the address of the remote side of the connection
+ to \a address.
+
+ You can call this function in a subclass of QAbstractSocket to
+ change the return value of the peerAddress() function after a
+ connection has been established. This feature is commonly used by
+ proxy connections for virtual connection settings.
+
+ \sa peerAddress(), setPeerPort(), setLocalAddress()
+*/
+void QAbstractSocket::setPeerAddress(const QHostAddress &address)
+{
+ Q_D(QAbstractSocket);
+ d->peerAddress = address;
+}
+
+/*!
+ \since 4.1
+
+ Sets the host name of the remote peer to \a name.
+
+ You can call this function in a subclass of QAbstractSocket to
+ change the return value of the peerName() function after a
+ connection has been established. This feature is commonly used by
+ proxy connections for virtual connection settings.
+
+ \sa peerName()
+*/
+void QAbstractSocket::setPeerName(const QString &name)
+{
+ Q_D(QAbstractSocket);
+ d->peerName = name;
+}
+
+/*!
+ Closes the I/O device for the socket, disconnects the socket's connection with the
+ host, closes the socket, and resets the name, address, port number and underlying
+ socket descriptor.
+
+ See QIODevice::close() for a description of the actions that occur when an I/O
+ device is closed.
+
+ \sa abort()
+*/
+void QAbstractSocket::close()
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::close()");
+#endif
+ QIODevice::close();
+ if (d->state != UnconnectedState) {
+ d->closeCalled = true;
+ disconnectFromHost();
+ }
+
+ d->localPort = 0;
+ d->peerPort = 0;
+ d->localAddress.clear();
+ d->peerAddress.clear();
+ d->peerName.clear();
+ d->cachedSocketDescriptor = -1;
+}
+
+/*!
+ Attempts to close the socket. If there is pending data waiting to
+ be written, QAbstractSocket will enter ClosingState and wait
+ until all data has been written. Eventually, it will enter
+ UnconnectedState and emit the disconnected() signal.
+
+ \sa connectToHost()
+*/
+void QAbstractSocket::disconnectFromHost()
+{
+ QMetaObject::invokeMethod(this, "disconnectFromHostImplementation",
+ Qt::DirectConnection);
+}
+
+/*!
+ \since 4.1
+
+ Contains the implementation of disconnectFromHost().
+*/
+void QAbstractSocket::disconnectFromHostImplementation()
+{
+ Q_D(QAbstractSocket);
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost()");
+#endif
+
+ if (d->state == UnconnectedState) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() was called on an unconnected socket");
+#endif
+ return;
+ }
+
+ if (!d->abortCalled && (d->state == ConnectingState || d->state == HostLookupState)) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() but we're still connecting");
+#endif
+ d->pendingClose = true;
+ return;
+ }
+
+#ifdef QT3_SUPPORT
+ emit connectionClosed(); // compat signal
+#endif
+
+ // Disable and delete read notification
+ if (d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(false);
+
+ if (d->abortCalled) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() aborting immediately");
+#endif
+ if (d->state == HostLookupState) {
+ QHostInfo::abortHostLookup(d->hostLookupId);
+ d->hostLookupId = -1;
+ }
+ } else {
+ // Perhaps emit closing()
+ if (d->state != ClosingState) {
+ d->state = ClosingState;
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() emits stateChanged()(ClosingState)");
+#endif
+ emit stateChanged(d->state);
+ } else {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() return from delayed close");
+#endif
+ }
+
+ // Wait for pending data to be written.
+ if (d->socketEngine && d->socketEngine->isValid() && (d->writeBuffer.size() > 0
+ || d->socketEngine->bytesToWrite() > 0)) {
+ // hack: when we are waiting for the socket engine to write bytes (only
+ // possible when using Socks5 or HTTP socket engine), then close
+ // anyway after 2 seconds. This is to prevent a timeout on Mac, where we
+ // sometimes just did not get the write notifier from the underlying
+ // CFSocket and no progress was made.
+ if (d->writeBuffer.size() == 0 && d->socketEngine->bytesToWrite() > 0) {
+ if (!d->disconnectTimer) {
+ d->disconnectTimer = new QTimer(this);
+ connect(d->disconnectTimer, SIGNAL(timeout()), this,
+ SLOT(_q_forceDisconnect()), Qt::DirectConnection);
+ }
+ if (!d->disconnectTimer->isActive())
+ d->disconnectTimer->start(2000);
+ }
+ d->socketEngine->setWriteNotificationEnabled(true);
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() delaying disconnect");
+#endif
+ return;
+ } else {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() disconnecting immediately");
+#endif
+ }
+ }
+
+ SocketState previousState = d->state;
+ d->resetSocketLayer();
+ d->state = UnconnectedState;
+ emit stateChanged(d->state);
+ emit readChannelFinished(); // we got an EOF
+
+#ifdef QT3_SUPPORT
+ emit delayedCloseFinished(); // compat signal
+#endif
+ // only emit disconnected if we were connected before
+ if (previousState == ConnectedState || previousState == ClosingState)
+ emit disconnected();
+
+ d->localPort = 0;
+ d->peerPort = 0;
+ d->localAddress.clear();
+ d->peerAddress.clear();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() disconnected!");
+#endif
+
+ if (d->closeCalled) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::disconnectFromHost() closed!");
+#endif
+ d->readBuffer.clear();
+ d->writeBuffer.clear();
+ QIODevice::close();
+ }
+}
+
+/*!
+ Returns the size of the internal read buffer. This limits the
+ amount of data that the client can receive before you call read()
+ or readAll().
+
+ A read buffer size of 0 (the default) means that the buffer has
+ no size limit, ensuring that no data is lost.
+
+ \sa setReadBufferSize(), read()
+*/
+qint64 QAbstractSocket::readBufferSize() const
+{
+ return d_func()->readBufferMaxSize;
+}
+
+/*!
+ Sets the size of QAbstractSocket's internal read buffer to be \a
+ size bytes.
+
+ If the buffer size is limited to a certain size, QAbstractSocket
+ won't buffer more than this size of data. Exceptionally, a buffer
+ size of 0 means that the read buffer is unlimited and all
+ incoming data is buffered. This is the default.
+
+ This option is useful if you only read the data at certain points
+ in time (e.g., in a real-time streaming application) or if you
+ want to protect your socket against receiving too much data,
+ which may eventually cause your application to run out of memory.
+
+ Only QTcpSocket uses QAbstractSocket's internal buffer; QUdpSocket
+ does not use any buffering at all, but rather relies on the
+ implicit buffering provided by the operating system.
+ Because of this, calling this function on QUdpSocket has no
+ effect.
+
+ \sa readBufferSize(), read()
+*/
+void QAbstractSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QAbstractSocket);
+
+#ifndef QT_NO_OPENSSL
+ // Manual polymorphism; setReadBufferSize() isn't virtual, but QSslSocket overloads
+ // it.
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this)) {
+ socket->setReadBufferSize(size);
+ return;
+ }
+#endif
+
+ if (d->readBufferMaxSize == size)
+ return;
+ d->readBufferMaxSize = size;
+ if (!d->readSocketNotifierCalled && d->socketEngine) {
+ // ensure that the read notification is enabled if we've now got
+ // room in the read buffer
+ // but only if we're not inside canReadNotification -- that will take care on its own
+ if ((size == 0 || d->readBuffer.size() < size) && d->state == QAbstractSocket::ConnectedState) // Do not change the notifier unless we are connected.
+ d->socketEngine->setReadNotificationEnabled(true);
+ }
+}
+
+/*!
+ Returns the state of the socket.
+
+ \sa error()
+*/
+QAbstractSocket::SocketState QAbstractSocket::state() const
+{
+ return d_func()->state;
+}
+
+/*!
+ Sets the state of the socket to \a state.
+
+ \sa state()
+*/
+void QAbstractSocket::setSocketState(SocketState state)
+{
+ d_func()->state = state;
+}
+
+/*!
+ Returns the socket type (TCP, UDP, or other).
+
+ \sa QTcpSocket, QUdpSocket
+*/
+QAbstractSocket::SocketType QAbstractSocket::socketType() const
+{
+ return d_func()->socketType;
+}
+
+/*!
+ Returns the type of error that last occurred.
+
+ \sa state(), errorString()
+*/
+QAbstractSocket::SocketError QAbstractSocket::error() const
+{
+ return d_func()->socketError;
+}
+
+/*!
+ Sets the type of error that last occurred to \a socketError.
+
+ \sa setSocketState(), setErrorString()
+*/
+void QAbstractSocket::setSocketError(SocketError socketError)
+{
+ d_func()->socketError = socketError;
+}
+
+#ifndef QT_NO_NETWORKPROXY
+/*!
+ \since 4.1
+
+ Sets the explicit network proxy for this socket to \a networkProxy.
+
+ To disable the use of a proxy for this socket, use the
+ QNetworkProxy::NoProxy proxy type:
+
+ \snippet doc/src/snippets/code/src_network_socket_qabstractsocket.cpp 3
+
+ The default value for the proxy is QNetworkProxy::DefaultProxy,
+ which means the socket will use the application settings: if a
+ proxy is set with QNetworkProxy::setApplicationProxy, it will use
+ that; otherwise, if a factory is set with
+ QNetworkProxyFactory::setApplicationProxyFactory, it will query
+ that factory with type QNetworkProxyQuery::TcpSocket.
+
+ \sa proxy(), QNetworkProxy, QNetworkProxyFactory::queryProxy()
+*/
+void QAbstractSocket::setProxy(const QNetworkProxy &networkProxy)
+{
+ Q_D(QAbstractSocket);
+ d->proxy = networkProxy;
+}
+
+/*!
+ \since 4.1
+
+ Returns the network proxy for this socket.
+ By default QNetworkProxy::DefaultProxy is used, which means this
+ socket will query the default proxy settings for the application.
+
+ \sa setProxy(), QNetworkProxy, QNetworkProxyFactory
+*/
+QNetworkProxy QAbstractSocket::proxy() const
+{
+ Q_D(const QAbstractSocket);
+ return d->proxy;
+}
+#endif // QT_NO_NETWORKPROXY
+
+#ifdef QT3_SUPPORT
+/*!
+ \enum QAbstractSocket::Error
+ \compat
+
+ Use QAbstractSocket::SocketError instead.
+
+ \value ErrConnectionRefused Use QAbstractSocket::ConnectionRefusedError instead.
+ \value ErrHostNotFound Use QAbstractSocket::HostNotFoundError instead.
+ \value ErrSocketRead Use QAbstractSocket::UnknownSocketError instead.
+*/
+
+/*!
+ \typedef QAbstractSocket::State
+ \compat
+
+ Use QAbstractSocket::SocketState instead.
+
+ \table
+ \header \o Qt 3 enum value \o Qt 4 enum value
+ \row \o \c Idle \o \l UnconnectedState
+ \row \o \c HostLookup \o \l HostLookupState
+ \row \o \c Connecting \o \l ConnectingState
+ \row \o \c Connected \o \l ConnectedState
+ \row \o \c Closing \o \l ClosingState
+ \row \o \c Connection \o \l ConnectedState
+ \endtable
+*/
+
+/*!
+ \fn int QAbstractSocket::socket() const
+
+ Use socketDescriptor() instead.
+*/
+
+/*!
+ \fn void QAbstractSocket::setSocket(int socket)
+
+ Use setSocketDescriptor() instead.
+*/
+
+/*!
+ \fn Q_ULONG QAbstractSocket::waitForMore(int msecs, bool *timeout = 0) const
+
+ Use waitForReadyRead() instead.
+
+ \oldcode
+ bool timeout;
+ Q_ULONG numBytes = socket->waitForMore(30000, &timeout);
+ \newcode
+ qint64 numBytes = 0;
+ if (socket->waitForReadyRead(msecs))
+ numBytes = socket->bytesAvailable();
+ bool timeout = (error() == QAbstractSocket::SocketTimeoutError);
+ \endcode
+
+ \sa waitForReadyRead(), bytesAvailable(), error(), SocketTimeoutError
+*/
+
+/*!
+ \fn void QAbstractSocket::connectionClosed()
+
+ Use disconnected() instead.
+*/
+
+/*!
+ \fn void QAbstractSocket::delayedCloseFinished()
+
+ Use disconnected() instead.
+*/
+#endif // QT3_SUPPORT
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketError error)
+{
+ switch (error) {
+ case QAbstractSocket::ConnectionRefusedError:
+ debug << "QAbstractSocket::ConnectionRefusedError";
+ break;
+ case QAbstractSocket::RemoteHostClosedError:
+ debug << "QAbstractSocket::RemoteHostClosedError";
+ break;
+ case QAbstractSocket::HostNotFoundError:
+ debug << "QAbstractSocket::HostNotFoundError";
+ break;
+ case QAbstractSocket::SocketAccessError:
+ debug << "QAbstractSocket::SocketAccessError";
+ break;
+ case QAbstractSocket::SocketResourceError:
+ debug << "QAbstractSocket::SocketResourceError";
+ break;
+ case QAbstractSocket::SocketTimeoutError:
+ debug << "QAbstractSocket::SocketTimeoutError";
+ break;
+ case QAbstractSocket::DatagramTooLargeError:
+ debug << "QAbstractSocket::DatagramTooLargeError";
+ break;
+ case QAbstractSocket::NetworkError:
+ debug << "QAbstractSocket::NetworkError";
+ break;
+ case QAbstractSocket::AddressInUseError:
+ debug << "QAbstractSocket::AddressInUseError";
+ break;
+ case QAbstractSocket::SocketAddressNotAvailableError:
+ debug << "QAbstractSocket::SocketAddressNotAvailableError";
+ break;
+ case QAbstractSocket::UnsupportedSocketOperationError:
+ debug << "QAbstractSocket::UnsupportedSocketOperationError";
+ break;
+ case QAbstractSocket::UnfinishedSocketOperationError:
+ debug << "QAbstractSocket::UnfinishedSocketOperationError";
+ break;
+ case QAbstractSocket::ProxyAuthenticationRequiredError:
+ debug << "QAbstractSocket::ProxyAuthenticationRequiredError";
+ break;
+ case QAbstractSocket::UnknownSocketError:
+ debug << "QAbstractSocket::UnknownSocketError";
+ break;
+ case QAbstractSocket::ProxyConnectionRefusedError:
+ debug << "QAbstractSocket::ProxyConnectionRefusedError";
+ break;
+ case QAbstractSocket::ProxyConnectionClosedError:
+ debug << "QAbstractSocket::ProxyConnectionClosedError";
+ break;
+ case QAbstractSocket::ProxyConnectionTimeoutError:
+ debug << "QAbstractSocket::ProxyConnectionTimeoutError";
+ break;
+ case QAbstractSocket::ProxyNotFoundError:
+ debug << "QAbstractSocket::ProxyNotFoundError";
+ break;
+ case QAbstractSocket::ProxyProtocolError:
+ debug << "QAbstractSocket::ProxyProtocolError";
+ break;
+ default:
+ debug << "QAbstractSocket::SocketError(" << int(error) << ')';
+ break;
+ }
+ return debug;
+}
+
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketState state)
+{
+ switch (state) {
+ case QAbstractSocket::UnconnectedState:
+ debug << "QAbstractSocket::UnconnectedState";
+ break;
+ case QAbstractSocket::HostLookupState:
+ debug << "QAbstractSocket::HostLookupState";
+ break;
+ case QAbstractSocket::ConnectingState:
+ debug << "QAbstractSocket::ConnectingState";
+ break;
+ case QAbstractSocket::ConnectedState:
+ debug << "QAbstractSocket::ConnectedState";
+ break;
+ case QAbstractSocket::BoundState:
+ debug << "QAbstractSocket::BoundState";
+ break;
+ case QAbstractSocket::ListeningState:
+ debug << "QAbstractSocket::ListeningState";
+ break;
+ case QAbstractSocket::ClosingState:
+ debug << "QAbstractSocket::ClosingState";
+ break;
+ default:
+ debug << "QAbstractSocket::SocketState(" << int(state) << ')';
+ break;
+ }
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractsocket.cpp"
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
new file mode 100644
index 0000000000..24f5478911
--- /dev/null
+++ b/src/network/socket/qabstractsocket.h
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSOCKET_H
+#define QABSTRACTSOCKET_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qobject.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QHostAddress;
+#ifndef QT_NO_NETWORKPROXY
+class QNetworkProxy;
+#endif
+class QAbstractSocketPrivate;
+class QAuthenticator;
+
+class Q_NETWORK_EXPORT QAbstractSocket : public QIODevice
+{
+ Q_OBJECT
+ Q_ENUMS(SocketType NetworkLayerProtocol SocketError SocketState SocketOption)
+public:
+ enum SocketType {
+ TcpSocket,
+ UdpSocket,
+ UnknownSocketType = -1
+ };
+ enum NetworkLayerProtocol {
+ IPv4Protocol,
+ IPv6Protocol,
+ UnknownNetworkLayerProtocol = -1
+ };
+ enum SocketError {
+ ConnectionRefusedError,
+ RemoteHostClosedError,
+ HostNotFoundError,
+ SocketAccessError,
+ SocketResourceError,
+ SocketTimeoutError, /* 5 */
+ DatagramTooLargeError,
+ NetworkError,
+ AddressInUseError,
+ SocketAddressNotAvailableError,
+ UnsupportedSocketOperationError, /* 10 */
+ UnfinishedSocketOperationError,
+ ProxyAuthenticationRequiredError,
+ SslHandshakeFailedError,
+ ProxyConnectionRefusedError,
+ ProxyConnectionClosedError, /* 15 */
+ ProxyConnectionTimeoutError,
+ ProxyNotFoundError,
+ ProxyProtocolError,
+
+ UnknownSocketError = -1
+ };
+ enum SocketState {
+ UnconnectedState,
+ HostLookupState,
+ ConnectingState,
+ ConnectedState,
+ BoundState,
+ ListeningState,
+ ClosingState
+#ifdef QT3_SUPPORT
+ ,
+ Idle = UnconnectedState,
+ HostLookup = HostLookupState,
+ Connecting = ConnectingState,
+ Connected = ConnectedState,
+ Closing = ClosingState,
+ Connection = ConnectedState
+#endif
+ };
+ enum SocketOption {
+ LowDelayOption, // TCP_NODELAY
+ KeepAliveOption, // SO_KEEPALIVE
+ MulticastTtlOption, // IP_MULTICAST_TTL
+ MulticastLoopbackOption // IP_MULTICAST_LOOPBACK
+ };
+
+ QAbstractSocket(SocketType socketType, QObject *parent);
+ virtual ~QAbstractSocket();
+
+ // ### Qt 5: Make connectToHost() and disconnectFromHost() virtual.
+ void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite);
+ void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
+ void disconnectFromHost();
+
+ bool isValid() const;
+
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+
+ bool canReadLine() const;
+
+ quint16 localPort() const;
+ QHostAddress localAddress() const;
+ quint16 peerPort() const;
+ QHostAddress peerAddress() const;
+ QString peerName() const;
+
+ // ### Qt 5: Make setReadBufferSize() virtual
+ qint64 readBufferSize() const;
+ void setReadBufferSize(qint64 size);
+
+ void abort();
+
+ // ### Qt 5: Make socketDescriptor() and setSocketDescriptor() virtual.
+ int socketDescriptor() const;
+ bool setSocketDescriptor(int socketDescriptor, SocketState state = ConnectedState,
+ OpenMode openMode = ReadWrite);
+
+ // ### Qt 5: Make virtual?
+ void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value);
+ QVariant socketOption(QAbstractSocket::SocketOption option);
+
+ SocketType socketType() const;
+ SocketState state() const;
+ SocketError error() const;
+
+ // from QIODevice
+ void close();
+ bool isSequential() const;
+ bool atEnd() const;
+ bool flush();
+
+ // for synchronous access
+ // ### Qt 5: Make waitForConnected() and waitForDisconnected() virtual.
+ bool waitForConnected(int msecs = 30000);
+ bool waitForReadyRead(int msecs = 30000);
+ bool waitForBytesWritten(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+
+#ifndef QT_NO_NETWORKPROXY
+ void setProxy(const QNetworkProxy &networkProxy);
+ QNetworkProxy proxy() const;
+#endif
+
+Q_SIGNALS:
+ void hostFound();
+ void connected();
+ void disconnected();
+ void stateChanged(QAbstractSocket::SocketState);
+ void error(QAbstractSocket::SocketError);
+#ifndef QT_NO_NETWORKPROXY
+ void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
+#endif
+
+protected Q_SLOTS:
+ void connectToHostImplementation(const QString &hostName, quint16 port, OpenMode mode = ReadWrite);
+ void disconnectFromHostImplementation();
+
+protected:
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 readLineData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+ void setSocketState(SocketState state);
+ void setSocketError(SocketError socketError);
+ void setLocalPort(quint16 port);
+ void setLocalAddress(const QHostAddress &address);
+ void setPeerPort(quint16 port);
+ void setPeerAddress(const QHostAddress &address);
+ void setPeerName(const QString &name);
+
+ QAbstractSocket(SocketType socketType, QAbstractSocketPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractSocket)
+ Q_DISABLE_COPY(QAbstractSocket)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_connectToNextAddress())
+ Q_PRIVATE_SLOT(d_func(), void _q_startConnecting(const QHostInfo &))
+ Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt())
+ Q_PRIVATE_SLOT(d_func(), void _q_testConnection())
+ Q_PRIVATE_SLOT(d_func(), void _q_forceDisconnect())
+
+#ifdef QT3_SUPPORT
+public:
+ enum Error {
+ ErrConnectionRefused = ConnectionRefusedError,
+ ErrHostNotFound = HostNotFoundError,
+ ErrSocketRead = UnknownSocketError
+ };
+ inline QT3_SUPPORT int socket() const { return socketDescriptor(); }
+ inline QT3_SUPPORT void setSocket(int socket) { setSocketDescriptor(socket); }
+ inline QT3_SUPPORT qulonglong waitForMore(int msecs, bool *timeout = 0) const
+ {
+ QAbstractSocket *that = const_cast<QAbstractSocket *>(this);
+ if (that->waitForReadyRead(msecs))
+ return qulonglong(bytesAvailable());
+ if (error() == SocketTimeoutError && timeout)
+ *timeout = true;
+ return 0;
+ }
+ typedef SocketState State;
+Q_SIGNALS:
+ QT_MOC_COMPAT void connectionClosed(); // same as disconnected()
+ QT_MOC_COMPAT void delayedCloseFinished(); // same as disconnected()
+
+
+#endif
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_NETWORK_EXPORT QDebug operator<<(QDebug, QAbstractSocket::SocketError);
+Q_NETWORK_EXPORT QDebug operator<<(QDebug, QAbstractSocket::SocketState);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTSOCKET_H
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
new file mode 100644
index 0000000000..7662f47fbf
--- /dev/null
+++ b/src/network/socket/qabstractsocket_p.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSOCKET_P_H
+#define QABSTRACTSOCKET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QAbstractSocket class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtNetwork/qabstractsocket.h"
+#include "QtCore/qbytearray.h"
+#include "QtCore/qlist.h"
+#include "QtCore/qtimer.h"
+#include "private/qringbuffer_p.h"
+#include "private/qiodevice_p.h"
+#include "private/qabstractsocketengine_p.h"
+#include "qnetworkproxy.h"
+
+QT_BEGIN_NAMESPACE
+
+class QHostInfo;
+
+class QAbstractSocketPrivate : public QIODevicePrivate, public QAbstractSocketEngineReceiver
+{
+ Q_DECLARE_PUBLIC(QAbstractSocket)
+public:
+ QAbstractSocketPrivate();
+ virtual ~QAbstractSocketPrivate();
+
+ // from QAbstractSocketEngineReceiver
+ inline void readNotification() { canReadNotification(); }
+ inline void writeNotification() { canWriteNotification(); }
+ inline void exceptionNotification() {}
+ void connectionNotification();
+#ifndef QT_NO_NETWORKPROXY
+ inline void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) {
+ Q_Q(QAbstractSocket);
+ q->proxyAuthenticationRequired(proxy, authenticator);
+ }
+#endif
+
+ bool canReadNotification();
+ bool canWriteNotification();
+
+ // slots
+ void _q_connectToNextAddress();
+ void _q_startConnecting(const QHostInfo &hostInfo);
+ void _q_testConnection();
+ void _q_abortConnectionAttempt();
+ void _q_forceDisconnect();
+
+ bool readSocketNotifierCalled;
+ bool readSocketNotifierState;
+ bool readSocketNotifierStateSet;
+
+ bool emittedReadyRead;
+ bool emittedBytesWritten;
+
+ bool abortCalled;
+ bool closeCalled;
+ bool pendingClose;
+
+ QString hostName;
+ quint16 port;
+ QHostAddress host;
+ QList<QHostAddress> addresses;
+
+ quint16 localPort;
+ quint16 peerPort;
+ QHostAddress localAddress;
+ QHostAddress peerAddress;
+ QString peerName;
+
+ QAbstractSocketEngine *socketEngine;
+ int cachedSocketDescriptor;
+
+#ifndef QT_NO_NETWORKPROXY
+ QNetworkProxy proxy;
+ QNetworkProxy proxyInUse;
+ void resolveProxy(const QString &hostName, quint16 port);
+#else
+ inline void resolveProxy(const QString &, quint16) { }
+#endif
+ inline void resolveProxy(quint16 port) { resolveProxy(QString(), port); }
+
+ void resetSocketLayer();
+ bool flush();
+
+ bool initSocketLayer(QAbstractSocket::NetworkLayerProtocol protocol);
+ void startConnectingByName(const QString &host);
+ void fetchConnectionParameters();
+ void setupSocketNotifiers();
+ bool readFromSocket();
+
+ qint64 readBufferMaxSize;
+ QRingBuffer readBuffer;
+ QRingBuffer writeBuffer;
+
+ bool isBuffered;
+ int blockingTimeout;
+
+ QTimer *connectTimer;
+ QTimer *disconnectTimer;
+ int connectTimeElapsed;
+
+ int hostLookupId;
+
+ QAbstractSocket::SocketType socketType;
+ QAbstractSocket::SocketState state;
+
+ QAbstractSocket::SocketError socketError;
+
+ bool prePauseReadSocketNotifierState;
+ bool prePauseWriteSocketNotifierState;
+ bool prePauseExceptionSocketNotifierState;
+ static void pauseSocketNotifiers(QAbstractSocket*);
+ static void resumeSocketNotifiers(QAbstractSocket*);
+ static QAbstractSocketEngine* getSocketEngine(QAbstractSocket*);
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTSOCKET_P_H
diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp
new file mode 100644
index 0000000000..c29f936923
--- /dev/null
+++ b/src/network/socket/qabstractsocketengine.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractsocketengine_p.h"
+
+#ifdef Q_OS_SYMBIAN
+#include "qsymbiansocketengine_p.h"
+#else
+#include "qnativesocketengine_p.h"
+#endif
+
+#include "qmutex.h"
+#include "qnetworkproxy.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSocketEngineHandlerList : public QList<QSocketEngineHandler*>
+{
+public:
+ QMutex mutex;
+};
+
+Q_GLOBAL_STATIC(QSocketEngineHandlerList, socketHandlers)
+
+QSocketEngineHandler::QSocketEngineHandler()
+{
+ if (!socketHandlers())
+ return;
+ QMutexLocker locker(&socketHandlers()->mutex);
+ socketHandlers()->prepend(this);
+}
+
+QSocketEngineHandler::~QSocketEngineHandler()
+{
+ if (!socketHandlers())
+ return;
+ QMutexLocker locker(&socketHandlers()->mutex);
+ socketHandlers()->removeAll(this);
+}
+
+QAbstractSocketEnginePrivate::QAbstractSocketEnginePrivate()
+ : socketError(QAbstractSocket::UnknownSocketError)
+ , hasSetSocketError(false)
+ , socketErrorString(QLatin1String(QT_TRANSLATE_NOOP(QSocketLayer, "Unknown error")))
+ , socketState(QAbstractSocket::UnconnectedState)
+ , socketType(QAbstractSocket::UnknownSocketType)
+ , socketProtocol(QAbstractSocket::UnknownNetworkLayerProtocol)
+ , localPort(0)
+ , peerPort(0)
+ , receiver(0)
+{
+}
+
+QAbstractSocketEngine::QAbstractSocketEngine(QObject *parent)
+ : QObject(*new QAbstractSocketEnginePrivate(), parent)
+{
+}
+
+QAbstractSocketEngine::QAbstractSocketEngine(QAbstractSocketEnginePrivate &dd, QObject* parent)
+ : QObject(dd, parent)
+{
+}
+
+QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &proxy, QObject *parent)
+{
+#ifndef QT_NO_NETWORKPROXY
+ // proxy type must have been resolved by now
+ if (proxy.type() == QNetworkProxy::DefaultProxy)
+ return 0;
+#endif
+
+ QMutexLocker locker(&socketHandlers()->mutex);
+ for (int i = 0; i < socketHandlers()->size(); i++) {
+ if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketType, proxy, parent))
+ return ret;
+ }
+
+#ifndef QT_NO_NETWORKPROXY
+ // only NoProxy can have reached here
+ if (proxy.type() != QNetworkProxy::NoProxy)
+ return 0;
+#endif
+
+#ifdef Q_OS_SYMBIAN
+ return new QSymbianSocketEngine(parent);
+#else
+ return new QNativeSocketEngine(parent);
+#endif
+}
+
+QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescripter, QObject *parent)
+{
+ QMutexLocker locker(&socketHandlers()->mutex);
+ for (int i = 0; i < socketHandlers()->size(); i++) {
+ if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketDescripter, parent))
+ return ret;
+ }
+#ifdef Q_OS_SYMBIAN
+ return new QSymbianSocketEngine(parent);
+#else
+ return new QNativeSocketEngine(parent);
+#endif
+}
+
+QAbstractSocket::SocketError QAbstractSocketEngine::error() const
+{
+ return d_func()->socketError;
+}
+
+QString QAbstractSocketEngine::errorString() const
+{
+ return d_func()->socketErrorString;
+}
+
+void QAbstractSocketEngine::setError(QAbstractSocket::SocketError error, const QString &errorString) const
+{
+ Q_D(const QAbstractSocketEngine);
+ d->socketError = error;
+ d->socketErrorString = errorString;
+}
+
+void QAbstractSocketEngine::setReceiver(QAbstractSocketEngineReceiver *receiver)
+{
+ d_func()->receiver = receiver;
+}
+
+void QAbstractSocketEngine::readNotification()
+{
+ if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver)
+ receiver->readNotification();
+}
+
+void QAbstractSocketEngine::writeNotification()
+{
+ if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver)
+ receiver->writeNotification();
+}
+
+void QAbstractSocketEngine::exceptionNotification()
+{
+ if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver)
+ receiver->exceptionNotification();
+}
+
+void QAbstractSocketEngine::connectionNotification()
+{
+ if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver)
+ receiver->connectionNotification();
+}
+
+#ifndef QT_NO_NETWORKPROXY
+void QAbstractSocketEngine::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
+{
+ if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver)
+ receiver->proxyAuthenticationRequired(proxy, authenticator);
+}
+#endif
+
+
+QAbstractSocket::SocketState QAbstractSocketEngine::state() const
+{
+ return d_func()->socketState;
+}
+
+void QAbstractSocketEngine::setState(QAbstractSocket::SocketState state)
+{
+ d_func()->socketState = state;
+}
+
+QAbstractSocket::SocketType QAbstractSocketEngine::socketType() const
+{
+ return d_func()->socketType;
+}
+
+void QAbstractSocketEngine::setSocketType(QAbstractSocket::SocketType socketType)
+{
+ d_func()->socketType = socketType;
+}
+
+QAbstractSocket::NetworkLayerProtocol QAbstractSocketEngine::protocol() const
+{
+ return d_func()->socketProtocol;
+}
+
+void QAbstractSocketEngine::setProtocol(QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ d_func()->socketProtocol = protocol;
+}
+
+QHostAddress QAbstractSocketEngine::localAddress() const
+{
+ return d_func()->localAddress;
+}
+
+void QAbstractSocketEngine::setLocalAddress(const QHostAddress &address)
+{
+ d_func()->localAddress = address;
+}
+
+quint16 QAbstractSocketEngine::localPort() const
+{
+ return d_func()->localPort;
+}
+
+void QAbstractSocketEngine::setLocalPort(quint16 port)
+{
+ d_func()->localPort = port;
+}
+
+QHostAddress QAbstractSocketEngine::peerAddress() const
+{
+ return d_func()->peerAddress;
+}
+
+void QAbstractSocketEngine::setPeerAddress(const QHostAddress &address)
+{
+ d_func()->peerAddress = address;
+}
+
+quint16 QAbstractSocketEngine::peerPort() const
+{
+ return d_func()->peerPort;
+}
+
+void QAbstractSocketEngine::setPeerPort(quint16 port)
+{
+ d_func()->peerPort = port;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
new file mode 100644
index 0000000000..ee6dad60d8
--- /dev/null
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSOCKETENGINE_P_H
+#define QABSTRACTSOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtNetwork/qhostaddress.h"
+#include "QtNetwork/qabstractsocket.h"
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAuthenticator;
+class QAbstractSocketEnginePrivate;
+#ifndef QT_NO_NETWORKINTERFACE
+class QNetworkInterface;
+#endif
+class QNetworkProxy;
+
+class QAbstractSocketEngineReceiver {
+public:
+ virtual ~QAbstractSocketEngineReceiver(){}
+ virtual void readNotification()= 0;
+ virtual void writeNotification()= 0;
+ virtual void exceptionNotification()= 0;
+ virtual void connectionNotification()= 0;
+#ifndef QT_NO_NETWORKPROXY
+ virtual void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)= 0;
+#endif
+};
+
+class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
+{
+ Q_OBJECT
+public:
+
+ static QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &, QObject *parent);
+ static QAbstractSocketEngine *createSocketEngine(int socketDescripter, QObject *parent);
+
+ QAbstractSocketEngine(QObject *parent = 0);
+
+ enum SocketOption {
+ NonBlockingSocketOption,
+ BroadcastSocketOption,
+ ReceiveBufferSocketOption,
+ SendBufferSocketOption,
+ AddressReusable,
+ BindExclusively,
+ ReceiveOutOfBandData,
+ LowDelayOption,
+ KeepAliveOption,
+ MulticastTtlOption,
+ MulticastLoopbackOption
+ };
+
+ virtual bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) = 0;
+
+ virtual bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) = 0;
+
+ virtual int socketDescriptor() const = 0;
+
+ virtual bool isValid() const = 0;
+
+ virtual bool connectToHost(const QHostAddress &address, quint16 port) = 0;
+ virtual bool connectToHostByName(const QString &name, quint16 port) = 0;
+ virtual bool bind(const QHostAddress &address, quint16 port) = 0;
+ virtual bool listen() = 0;
+ virtual int accept() = 0;
+ virtual void close() = 0;
+
+ virtual qint64 bytesAvailable() const = 0;
+
+ virtual qint64 read(char *data, qint64 maxlen) = 0;
+ virtual qint64 write(const char *data, qint64 len) = 0;
+
+#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ virtual bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface) = 0;
+ virtual bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface) = 0;
+ virtual QNetworkInterface multicastInterface() const = 0;
+ virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
+#endif // QT_NO_NETWORKINTERFACE
+
+ virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0) = 0;
+ virtual qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port) = 0;
+ virtual bool hasPendingDatagrams() const = 0;
+ virtual qint64 pendingDatagramSize() const = 0;
+#endif // QT_NO_UDPSOCKET
+
+ virtual qint64 bytesToWrite() const = 0;
+
+ virtual int option(SocketOption option) const = 0;
+ virtual bool setOption(SocketOption option, int value) = 0;
+
+ virtual bool waitForRead(int msecs = 30000, bool *timedOut = 0) = 0;
+ virtual bool waitForWrite(int msecs = 30000, bool *timedOut = 0) = 0;
+ virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0) = 0;
+
+ QAbstractSocket::SocketError error() const;
+ QString errorString() const;
+ QAbstractSocket::SocketState state() const;
+ QAbstractSocket::SocketType socketType() const;
+ QAbstractSocket::NetworkLayerProtocol protocol() const;
+
+ QHostAddress localAddress() const;
+ quint16 localPort() const;
+ QHostAddress peerAddress() const;
+ quint16 peerPort() const;
+
+ virtual bool isReadNotificationEnabled() const = 0;
+ virtual void setReadNotificationEnabled(bool enable) = 0;
+ virtual bool isWriteNotificationEnabled() const = 0;
+ virtual void setWriteNotificationEnabled(bool enable) = 0;
+ virtual bool isExceptionNotificationEnabled() const = 0;
+ virtual void setExceptionNotificationEnabled(bool enable) = 0;
+
+public Q_SLOTS:
+ void readNotification();
+ void writeNotification();
+ void exceptionNotification();
+ void connectionNotification();
+#ifndef QT_NO_NETWORKPROXY
+ void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
+#endif
+
+public:
+ void setReceiver(QAbstractSocketEngineReceiver *receiver);
+protected:
+ QAbstractSocketEngine(QAbstractSocketEnginePrivate &dd, QObject* parent = 0);
+
+ void setError(QAbstractSocket::SocketError error, const QString &errorString) const;
+ void setState(QAbstractSocket::SocketState state);
+ void setSocketType(QAbstractSocket::SocketType socketType);
+ void setProtocol(QAbstractSocket::NetworkLayerProtocol protocol);
+ void setLocalAddress(const QHostAddress &address);
+ void setLocalPort(quint16 port);
+ void setPeerAddress(const QHostAddress &address);
+ void setPeerPort(quint16 port);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractSocketEngine)
+ Q_DISABLE_COPY(QAbstractSocketEngine)
+};
+
+class QAbstractSocketEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractSocketEngine)
+public:
+ QAbstractSocketEnginePrivate();
+
+ mutable QAbstractSocket::SocketError socketError;
+ mutable bool hasSetSocketError;
+ mutable QString socketErrorString;
+ QAbstractSocket::SocketState socketState;
+ QAbstractSocket::SocketType socketType;
+ QAbstractSocket::NetworkLayerProtocol socketProtocol;
+ QHostAddress localAddress;
+ quint16 localPort;
+ QHostAddress peerAddress;
+ quint16 peerPort;
+ QAbstractSocketEngineReceiver *receiver;
+};
+
+
+class Q_AUTOTEST_EXPORT QSocketEngineHandler
+{
+protected:
+ QSocketEngineHandler();
+ virtual ~QSocketEngineHandler();
+ virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType,
+ const QNetworkProxy &, QObject *parent) = 0;
+ virtual QAbstractSocketEngine *createSocketEngine(int socketDescripter, QObject *parent) = 0;
+
+private:
+ friend class QAbstractSocketEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTSOCKETENGINE_P_H
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
new file mode 100644
index 0000000000..7846056221
--- /dev/null
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -0,0 +1,824 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhttpsocketengine_p.h"
+#include "qtcpsocket.h"
+#include "qhostaddress.h"
+#include "qurl.h"
+#include "qhttp.h"
+#include "qelapsedtimer.h"
+#include "qnetworkinterface.h"
+
+#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP)
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#define DEBUG
+
+QHttpSocketEngine::QHttpSocketEngine(QObject *parent)
+ : QAbstractSocketEngine(*new QHttpSocketEnginePrivate, parent)
+{
+}
+
+QHttpSocketEngine::~QHttpSocketEngine()
+{
+}
+
+bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QHttpSocketEngine);
+ if (type != QAbstractSocket::TcpSocket)
+ return false;
+
+ setProtocol(protocol);
+ setSocketType(type);
+ d->socket = new QTcpSocket(this);
+#ifndef QT_NO_BEARERMANAGEMENT
+ d->socket->setProperty("_q_networkSession", property("_q_networkSession"));
+#endif
+
+ // Explicitly disable proxying on the proxy socket itself to avoid
+ // unwanted recursion.
+ d->socket->setProxy(QNetworkProxy::NoProxy);
+
+ // Intercept all the signals.
+ connect(d->socket, SIGNAL(connected()),
+ this, SLOT(slotSocketConnected()),
+ Qt::DirectConnection);
+ connect(d->socket, SIGNAL(disconnected()),
+ this, SLOT(slotSocketDisconnected()),
+ Qt::DirectConnection);
+ connect(d->socket, SIGNAL(readyRead()),
+ this, SLOT(slotSocketReadNotification()),
+ Qt::DirectConnection);
+ connect(d->socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(slotSocketBytesWritten()),
+ Qt::DirectConnection);
+ connect(d->socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(slotSocketError(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+ connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(slotSocketStateChanged(QAbstractSocket::SocketState)),
+ Qt::DirectConnection);
+
+ return true;
+}
+
+bool QHttpSocketEngine::initialize(int, QAbstractSocket::SocketState)
+{
+ return false;
+}
+
+void QHttpSocketEngine::setProxy(const QNetworkProxy &proxy)
+{
+ Q_D(QHttpSocketEngine);
+ d->proxy = proxy;
+ QString user = proxy.user();
+ if (!user.isEmpty())
+ d->authenticator.setUser(user);
+ QString password = proxy.password();
+ if (!password.isEmpty())
+ d->authenticator.setPassword(password);
+}
+
+int QHttpSocketEngine::socketDescriptor() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->socket ? d->socket->socketDescriptor() : 0;
+}
+
+bool QHttpSocketEngine::isValid() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->socket;
+}
+
+bool QHttpSocketEngine::connectInternal()
+{
+ Q_D(QHttpSocketEngine);
+
+ // If the handshake is done, enter ConnectedState state and return true.
+ if (d->state == Connected) {
+ qWarning("QHttpSocketEngine::connectToHost: called when already connected");
+ setState(QAbstractSocket::ConnectedState);
+ return true;
+ }
+
+ if (d->state == ConnectSent && d->socketState != QAbstractSocket::ConnectedState)
+ setState(QAbstractSocket::UnconnectedState);
+
+ // Handshake isn't done. If unconnected, start connecting.
+ if (d->state == None && d->socket->state() == QAbstractSocket::UnconnectedState) {
+ setState(QAbstractSocket::ConnectingState);
+ d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
+ }
+
+ // If connected (might happen right away, at least for localhost services
+ // on some BSD systems), there might already be bytes available.
+ if (bytesAvailable())
+ slotSocketReadNotification();
+
+ return d->socketState == QAbstractSocket::ConnectedState;
+}
+
+bool QHttpSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
+{
+ Q_D(QHttpSocketEngine);
+
+ setPeerAddress(address);
+ setPeerPort(port);
+ d->peerName.clear();
+
+ return connectInternal();
+}
+
+bool QHttpSocketEngine::connectToHostByName(const QString &hostname, quint16 port)
+{
+ Q_D(QHttpSocketEngine);
+
+ setPeerAddress(QHostAddress());
+ setPeerPort(port);
+ d->peerName = hostname;
+
+ return connectInternal();
+}
+
+bool QHttpSocketEngine::bind(const QHostAddress &, quint16)
+{
+ return false;
+}
+
+bool QHttpSocketEngine::listen()
+{
+ return false;
+}
+
+int QHttpSocketEngine::accept()
+{
+ return 0;
+}
+
+void QHttpSocketEngine::close()
+{
+ Q_D(QHttpSocketEngine);
+ if (d->socket) {
+ d->socket->close();
+ delete d->socket;
+ d->socket = 0;
+ }
+}
+
+qint64 QHttpSocketEngine::bytesAvailable() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->readBuffer.size() + (d->socket ? d->socket->bytesAvailable() : 0);
+}
+
+qint64 QHttpSocketEngine::read(char *data, qint64 maxlen)
+{
+ Q_D(QHttpSocketEngine);
+ qint64 bytesRead = d->socket->read(data, maxlen);
+
+ if (d->socket->state() == QAbstractSocket::UnconnectedState
+ && d->socket->bytesAvailable() == 0) {
+ emitReadNotification();
+ }
+
+ if (bytesRead == -1) {
+ // If nothing has been read so far, and the direct socket read
+ // failed, return the socket's error. Otherwise, fall through and
+ // return as much as we read so far.
+ close();
+ setError(QAbstractSocket::RemoteHostClosedError,
+ QLatin1String("Remote host closed"));
+ setState(QAbstractSocket::UnconnectedState);
+ return -1;
+ }
+ return bytesRead;
+}
+
+qint64 QHttpSocketEngine::write(const char *data, qint64 len)
+{
+ Q_D(QHttpSocketEngine);
+ return d->socket->write(data, len);
+}
+
+#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+bool QHttpSocketEngine::joinMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+bool QHttpSocketEngine::leaveMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+QNetworkInterface QHttpSocketEngine::multicastInterface() const
+{
+ return QNetworkInterface();
+}
+
+bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+#endif // QT_NO_NETWORKINTERFACE
+
+qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *,
+ quint16 *)
+{
+ return 0;
+}
+
+qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QHostAddress &,
+ quint16)
+{
+ return 0;
+}
+
+bool QHttpSocketEngine::hasPendingDatagrams() const
+{
+ return false;
+}
+
+qint64 QHttpSocketEngine::pendingDatagramSize() const
+{
+ return 0;
+}
+#endif // QT_NO_UDPSOCKET
+
+qint64 QHttpSocketEngine::bytesToWrite() const
+{
+ Q_D(const QHttpSocketEngine);
+ if (d->socket) {
+ return d->socket->bytesToWrite();
+ } else {
+ return 0;
+ }
+}
+
+int QHttpSocketEngine::option(SocketOption option) const
+{
+ Q_D(const QHttpSocketEngine);
+ if (d->socket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ return d->socket->socketOption(QAbstractSocket::LowDelayOption).toInt();
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ return d->socket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
+ }
+ return -1;
+}
+
+bool QHttpSocketEngine::setOption(SocketOption option, int value)
+{
+ Q_D(QHttpSocketEngine);
+ if (d->socket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ d->socket->setSocketOption(QAbstractSocket::LowDelayOption, value);
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ d->socket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
+ return true;
+ }
+ return false;
+}
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(const QHttpSocketEngine);
+
+ if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
+ return false;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // Wait for more data if nothing is available.
+ if (!d->socket->bytesAvailable()) {
+ if (!d->socket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ if (d->socket->state() == QAbstractSocket::UnconnectedState)
+ return true;
+ setError(d->socket->error(), d->socket->errorString());
+ if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ return false;
+ }
+ }
+
+ // If we're not connected yet, wait until we are, or until an error
+ // occurs.
+ while (d->state != Connected && d->socket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ // Loop while the protocol handshake is taking place.
+ }
+
+ // Report any error that may occur.
+ if (d->state != Connected) {
+ setError(d->socket->error(), d->socket->errorString());
+ if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ return false;
+ }
+ return true;
+}
+
+bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_D(const QHttpSocketEngine);
+
+ // If we're connected, just forward the call.
+ if (d->state == Connected) {
+ if (d->socket->bytesToWrite()) {
+ if (!d->socket->waitForBytesWritten(msecs)) {
+ if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut)
+ *timedOut = true;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // If we're not connected yet, wait until we are, and until bytes have
+ // been received (i.e., the socket has connected, we have sent the
+ // greeting, and then received the response).
+ while (d->state != Connected && d->socket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ // Loop while the protocol handshake is taking place.
+ }
+
+ // Report any error that may occur.
+ if (d->state != Connected) {
+// setError(d->socket->error(), d->socket->errorString());
+ if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ }
+
+ return true;
+}
+
+bool QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_UNUSED(checkRead);
+
+ if (!checkWrite) {
+ // Not interested in writing? Then we wait for read notifications.
+ bool canRead = waitForRead(msecs, timedOut);
+ if (readyToRead)
+ *readyToRead = canRead;
+ return canRead;
+ }
+
+ // Interested in writing? Then we wait for write notifications.
+ bool canWrite = waitForWrite(msecs, timedOut);
+ if (readyToWrite)
+ *readyToWrite = canWrite;
+ return canWrite;
+}
+
+bool QHttpSocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->readNotificationEnabled;
+}
+
+void QHttpSocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QHttpSocketEngine);
+ if (d->readNotificationEnabled == enable)
+ return;
+
+ d->readNotificationEnabled = enable;
+ if (enable) {
+ // Enabling read notification can trigger a notification.
+ if (bytesAvailable())
+ slotSocketReadNotification();
+ }
+}
+
+bool QHttpSocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->writeNotificationEnabled;
+}
+
+void QHttpSocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QHttpSocketEngine);
+ d->writeNotificationEnabled = enable;
+ if (enable && d->state == Connected && d->socket->state() == QAbstractSocket::ConnectedState)
+ QMetaObject::invokeMethod(this, "writeNotification", Qt::QueuedConnection);
+}
+
+bool QHttpSocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QHttpSocketEngine);
+ return d->exceptNotificationEnabled;
+}
+
+void QHttpSocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QHttpSocketEngine);
+ d->exceptNotificationEnabled = enable;
+}
+
+void QHttpSocketEngine::slotSocketConnected()
+{
+ Q_D(QHttpSocketEngine);
+
+ // Send the greeting.
+ const char method[] = "CONNECT ";
+ QByteArray peerAddress = d->peerName.isEmpty() ?
+ d->peerAddress.toString().toLatin1() :
+ QUrl::toAce(d->peerName);
+ QByteArray path = peerAddress + ':' + QByteArray::number(d->peerPort);
+ QByteArray data = method;
+ data += path;
+ data += " HTTP/1.1\r\n";
+ data += "Proxy-Connection: keep-alive\r\n"
+ "User-Agent: Mozilla/5.0\r\n"
+ "Host: " + peerAddress + "\r\n";
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ //qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);
+ if (priv && priv->method != QAuthenticatorPrivate::None) {
+ data += "Proxy-Authorization: " + priv->calculateResponse(method, path);
+ data += "\r\n";
+ }
+ data += "\r\n";
+// qDebug() << ">>>>>>>> sending request" << this;
+// qDebug() << data;
+// qDebug() << ">>>>>>>";
+ d->socket->write(data);
+ d->state = ConnectSent;
+}
+
+void QHttpSocketEngine::slotSocketDisconnected()
+{
+}
+
+void QHttpSocketEngine::slotSocketReadNotification()
+{
+ Q_D(QHttpSocketEngine);
+ if (d->state != Connected && d->socket->bytesAvailable() == 0)
+ return;
+
+ if (d->state == Connected) {
+ // Forward as a read notification.
+ if (d->readNotificationEnabled)
+ emitReadNotification();
+ return;
+ }
+
+ readResponseContent:
+ if (d->state == ReadResponseContent) {
+ char dummybuffer[4096];
+ while (d->pendingResponseData) {
+ int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
+ if (read >= 0)
+ dummybuffer[read] = 0;
+
+ if (read == 0)
+ return;
+ if (read == -1) {
+ d->socket->disconnectFromHost();
+ emitWriteNotification();
+ return;
+ }
+ d->pendingResponseData -= read;
+ }
+ if (d->pendingResponseData > 0)
+ return;
+ d->state = SendAuthentication;
+ slotSocketConnected();
+ return;
+ }
+
+ // Still in handshake mode. Wait until we've got a full response.
+ bool done = false;
+ do {
+ d->readBuffer += d->socket->readLine();
+ } while (!(done = d->readBuffer.endsWith("\r\n\r\n")) && d->socket->canReadLine());
+
+ if (!done) {
+ // Wait for more.
+ return;
+ }
+
+ if (!d->readBuffer.startsWith("HTTP/1.")) {
+ // protocol error, this isn't HTTP
+ d->readBuffer.clear();
+ d->socket->close();
+ setState(QAbstractSocket::UnconnectedState);
+ setError(QAbstractSocket::ProxyProtocolError, tr("Did not receive HTTP response from proxy"));
+ emitConnectionNotification();
+ return;
+ }
+
+ QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer));
+ d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done
+
+ int statusCode = responseHeader.statusCode();
+ if (statusCode == 200) {
+ d->state = Connected;
+ setLocalAddress(d->socket->localAddress());
+ setLocalPort(d->socket->localPort());
+ setState(QAbstractSocket::ConnectedState);
+ } else if (statusCode == 407) {
+ if (d->authenticator.isNull())
+ d->authenticator.detach();
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+
+ priv->parseHttpResponse(responseHeader, true);
+
+ if (priv->phase == QAuthenticatorPrivate::Invalid) {
+ // problem parsing the reply
+ d->socket->close();
+ setState(QAbstractSocket::UnconnectedState);
+ setError(QAbstractSocket::ProxyProtocolError, tr("Error parsing authentication request from proxy"));
+ emitConnectionNotification();
+ return;
+ }
+
+ bool willClose;
+ QString proxyConnectionHeader = responseHeader.value(QLatin1String("Proxy-Connection"));
+ proxyConnectionHeader = proxyConnectionHeader.toLower();
+ if (proxyConnectionHeader == QLatin1String("close")) {
+ willClose = true;
+ } else if (proxyConnectionHeader == QLatin1String("keep-alive")) {
+ willClose = false;
+ } else {
+ // no Proxy-Connection header, so use the default
+ // HTTP 1.1's default behaviour is to keep persistent connections
+ // HTTP 1.0 or earlier, so we expect the server to close
+ willClose = (responseHeader.majorVersion() * 0x100 + responseHeader.minorVersion()) <= 0x0100;
+ }
+
+ if (willClose) {
+ // the server will disconnect, so let's avoid receiving an error
+ // especially since the signal below may trigger a new event loop
+ d->socket->disconnectFromHost();
+ d->socket->readAll();
+ }
+
+ if (priv->phase == QAuthenticatorPrivate::Done)
+ emit proxyAuthenticationRequired(d->proxy, &d->authenticator);
+
+ // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
+ if (priv->phase == QAuthenticatorPrivate::Done) {
+ setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
+ d->socket->disconnectFromHost();
+ } else {
+ // close the connection if it isn't already and reconnect using the chosen authentication method
+ d->state = SendAuthentication;
+ if (willClose) {
+ d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
+ } else {
+ bool ok;
+ int contentLength = responseHeader.value(QLatin1String("Content-Length")).toInt(&ok);
+ if (ok && contentLength > 0) {
+ d->state = ReadResponseContent;
+ d->pendingResponseData = contentLength;
+ goto readResponseContent;
+ } else {
+ d->state = SendAuthentication;
+ slotSocketConnected();
+ }
+ }
+ return;
+ }
+ } else {
+ d->socket->close();
+ setState(QAbstractSocket::UnconnectedState);
+ if (statusCode == 403 || statusCode == 405) {
+ // 403 Forbidden
+ // 405 Method Not Allowed
+ setError(QAbstractSocket::SocketAccessError, tr("Proxy denied connection"));
+ } else if (statusCode == 404) {
+ // 404 Not Found: host lookup error
+ setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr("Host not found"));
+ } else if (statusCode == 503) {
+ // 503 Service Unavailable: Connection Refused
+ setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
+ } else {
+ // Some other reply
+ //qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
+ setError(QAbstractSocket::ProxyProtocolError, tr("Error communicating with HTTP proxy"));
+ }
+ }
+
+ // The handshake is done; notify that we're connected (or failed to connect)
+ emitConnectionNotification();
+}
+
+void QHttpSocketEngine::slotSocketBytesWritten()
+{
+ Q_D(QHttpSocketEngine);
+ if (d->state == Connected && d->writeNotificationEnabled)
+ emitWriteNotification();
+}
+
+void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error)
+{
+ Q_D(QHttpSocketEngine);
+ d->readBuffer.clear();
+
+ if (d->state != Connected) {
+ // we are in proxy handshaking stages
+ if (error == QAbstractSocket::HostNotFoundError)
+ setError(QAbstractSocket::ProxyNotFoundError, tr("Proxy server not found"));
+ else if (error == QAbstractSocket::ConnectionRefusedError)
+ setError(QAbstractSocket::ProxyConnectionRefusedError, tr("Proxy connection refused"));
+ else if (error == QAbstractSocket::SocketTimeoutError)
+ setError(QAbstractSocket::ProxyConnectionTimeoutError, tr("Proxy server connection timed out"));
+ else if (error == QAbstractSocket::RemoteHostClosedError)
+ setError(QAbstractSocket::ProxyConnectionClosedError, tr("Proxy connection closed prematurely"));
+ else
+ setError(error, d->socket->errorString());
+ emitConnectionNotification();
+ return;
+ }
+
+ // We're connected
+ if (error == QAbstractSocket::SocketTimeoutError)
+ return; // ignore this error
+
+ d->state = None;
+ setError(error, d->socket->errorString());
+ if (error != QAbstractSocket::RemoteHostClosedError)
+ qDebug() << "QHttpSocketEngine::slotSocketError: got weird error =" << error;
+ //read notification needs to always be emitted, otherwise the higher layer doesn't get the disconnected signal
+ emitReadNotification();
+}
+
+void QHttpSocketEngine::slotSocketStateChanged(QAbstractSocket::SocketState state)
+{
+ Q_UNUSED(state);
+}
+
+void QHttpSocketEngine::emitPendingReadNotification()
+{
+ Q_D(QHttpSocketEngine);
+ d->readNotificationPending = false;
+ if (d->readNotificationEnabled)
+ emit readNotification();
+}
+
+void QHttpSocketEngine::emitPendingWriteNotification()
+{
+ Q_D(QHttpSocketEngine);
+ d->writeNotificationPending = false;
+ if (d->writeNotificationEnabled)
+ emit writeNotification();
+}
+
+void QHttpSocketEngine::emitPendingConnectionNotification()
+{
+ Q_D(QHttpSocketEngine);
+ d->connectionNotificationPending = false;
+ emit connectionNotification();
+}
+
+void QHttpSocketEngine::emitReadNotification()
+{
+ Q_D(QHttpSocketEngine);
+ d->readNotificationActivated = true;
+ // if there is a connection notification pending we have to emit the readNotification
+ // incase there is connection error. This is only needed for Windows, but it does not
+ // hurt in other cases.
+ if ((d->readNotificationEnabled && !d->readNotificationPending) || d->connectionNotificationPending) {
+ d->readNotificationPending = true;
+ QMetaObject::invokeMethod(this, "emitPendingReadNotification", Qt::QueuedConnection);
+ }
+}
+
+void QHttpSocketEngine::emitWriteNotification()
+{
+ Q_D(QHttpSocketEngine);
+ d->writeNotificationActivated = true;
+ if (d->writeNotificationEnabled && !d->writeNotificationPending) {
+ d->writeNotificationPending = true;
+ QMetaObject::invokeMethod(this, "emitPendingWriteNotification", Qt::QueuedConnection);
+ }
+}
+
+void QHttpSocketEngine::emitConnectionNotification()
+{
+ Q_D(QHttpSocketEngine);
+ if (!d->connectionNotificationPending) {
+ d->connectionNotificationPending = true;
+ QMetaObject::invokeMethod(this, "emitPendingConnectionNotification", Qt::QueuedConnection);
+ }
+}
+
+QHttpSocketEnginePrivate::QHttpSocketEnginePrivate()
+ : readNotificationEnabled(false)
+ , writeNotificationEnabled(false)
+ , exceptNotificationEnabled(false)
+ , readNotificationActivated(false)
+ , writeNotificationActivated(false)
+ , readNotificationPending(false)
+ , writeNotificationPending(false)
+ , connectionNotificationPending(false)
+ , pendingResponseData(0)
+{
+ socket = 0;
+ state = QHttpSocketEngine::None;
+}
+
+QHttpSocketEnginePrivate::~QHttpSocketEnginePrivate()
+{
+}
+
+QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
+ const QNetworkProxy &proxy,
+ QObject *parent)
+{
+ if (socketType != QAbstractSocket::TcpSocket)
+ return 0;
+
+ // proxy type must have been resolved by now
+ if (proxy.type() != QNetworkProxy::HttpProxy)
+ return 0;
+
+ // we only accept active sockets
+ if (!qobject_cast<QAbstractSocket *>(parent))
+ return 0;
+
+ QHttpSocketEngine *engine = new QHttpSocketEngine(parent);
+ engine->setProxy(proxy);
+ return engine;
+}
+
+QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(int, QObject *)
+{
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
new file mode 100644
index 0000000000..361ef5c693
--- /dev/null
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHTTPSOCKETENGINE_P_H
+#define QHTTPSOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qabstractsocketengine_p.h"
+#include "qabstractsocket.h"
+#include "qnetworkproxy.h"
+#include "private/qauthenticator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP)
+
+class QTcpSocket;
+class QHttpSocketEnginePrivate;
+
+class Q_AUTOTEST_EXPORT QHttpSocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+public:
+ enum HttpState {
+ None,
+ ConnectSent,
+ Connected,
+ SendAuthentication,
+ ReadResponseContent
+ };
+ QHttpSocketEngine(QObject *parent = 0);
+ ~QHttpSocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ void setProxy(const QNetworkProxy &networkProxy);
+
+ int socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectInternal();
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+ qint64 bytesAvailable() const;
+
+ qint64 read(char *data, qint64 maxlen);
+ qint64 write(const char *data, qint64 len);
+
+#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif // QT_NO_NETWORKINTERFACE
+
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+#endif // QT_NO_UDPSOCKET
+
+ qint64 bytesToWrite() const;
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+public slots:
+ void slotSocketConnected();
+ void slotSocketDisconnected();
+ void slotSocketReadNotification();
+ void slotSocketBytesWritten();
+ void slotSocketError(QAbstractSocket::SocketError error);
+ void slotSocketStateChanged(QAbstractSocket::SocketState state);
+
+private slots:
+ void emitPendingReadNotification();
+ void emitPendingWriteNotification();
+ void emitPendingConnectionNotification();
+
+private:
+ void emitReadNotification();
+ void emitWriteNotification();
+ void emitConnectionNotification();
+
+ Q_DECLARE_PRIVATE(QHttpSocketEngine)
+ Q_DISABLE_COPY(QHttpSocketEngine)
+
+};
+
+
+class QHttpSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QHttpSocketEngine)
+public:
+ QHttpSocketEnginePrivate();
+ ~QHttpSocketEnginePrivate();
+
+ QNetworkProxy proxy;
+ QString peerName;
+ QTcpSocket *socket;
+ QByteArray readBuffer; // only used for parsing the proxy response
+ QHttpSocketEngine::HttpState state;
+ QAuthenticator authenticator;
+ bool readNotificationEnabled;
+ bool writeNotificationEnabled;
+ bool exceptNotificationEnabled;
+ bool readNotificationActivated;
+ bool writeNotificationActivated;
+ bool readNotificationPending;
+ bool writeNotificationPending;
+ bool connectionNotificationPending;
+ uint pendingResponseData;
+};
+
+class Q_AUTOTEST_EXPORT QHttpSocketEngineHandler : public QSocketEngineHandler
+{
+public:
+ virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType,
+ const QNetworkProxy &, QObject *parent);
+ virtual QAbstractSocketEngine *createSocketEngine(int socketDescripter, QObject *parent);
+};
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QHTTPSOCKETENGINE_H
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
new file mode 100644
index 0000000000..46822d7bad
--- /dev/null
+++ b/src/network/socket/qlocalserver.cpp
@@ -0,0 +1,401 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LOCALSERVER
+
+/*!
+ \class QLocalServer
+ \since 4.4
+
+ \brief The QLocalServer class provides a local socket based server.
+
+ This class makes it possible to accept incoming local socket
+ connections.
+
+ Call listen() to have the server start listening
+ for incoming connections on a specified key. The
+ newConnection() signal is then emitted each time a client
+ connects to the server.
+
+ Call nextPendingConnection() to accept the pending connection
+ as a connected QLocalSocket. The function returns a pointer to a
+ QLocalSocket that can be used for communicating with the client.
+
+ If an error occurs, serverError() returns the type of error, and
+ errorString() can be called to get a human readable description
+ of what happened.
+
+ When listening for connections, the name which the server is
+ listening on is available through serverName().
+
+ Calling close() makes QLocalServer stop listening for incoming connections.
+
+ Although QLocalServer is designed for use with an event loop, it's possible
+ to use it without one. In that case, you must use waitForNewConnection(),
+ which blocks until either a connection is available or a timeout expires.
+
+ \sa QLocalSocket, QTcpServer
+*/
+
+/*!
+ Create a new local socket server with the given \a parent.
+
+ \sa listen()
+ */
+QLocalServer::QLocalServer(QObject *parent)
+ : QObject(*new QLocalServerPrivate, parent)
+{
+ Q_D(QLocalServer);
+ d->init();
+}
+
+/*!
+ Destroys the QLocalServer object. If the server is listening for
+ connections, it is automatically closed.
+
+ Any client QLocalSockets that are still connected must either
+ disconnect or be reparented before the server is deleted.
+
+ \sa close()
+ */
+QLocalServer::~QLocalServer()
+{
+ if (isListening())
+ close();
+}
+
+/*!
+ Stop listening for incoming connections. Existing connections are not
+ effected, but any new connections will be refused.
+
+ \sa isListening(), listen()
+ */
+void QLocalServer::close()
+{
+ Q_D(QLocalServer);
+ if (!isListening())
+ return;
+ qDeleteAll(d->pendingConnections);
+ d->pendingConnections.clear();
+ d->closeServer();
+ d->serverName.clear();
+ d->fullServerName.clear();
+ d->errorString.clear();
+ d->error = QAbstractSocket::UnknownSocketError;
+}
+
+/*!
+ Returns the human-readable message appropriate to the current error
+ reported by serverError(). If no suitable string is available, an empty
+ string is returned.
+
+ \sa serverError()
+ */
+QString QLocalServer::errorString() const
+{
+ Q_D(const QLocalServer);
+ return d->errorString;
+}
+
+/*!
+ Returns true if the server has a pending connection; otherwise
+ returns false.
+
+ \sa nextPendingConnection(), setMaxPendingConnections()
+ */
+bool QLocalServer::hasPendingConnections() const
+{
+ Q_D(const QLocalServer);
+ return !(d->pendingConnections.isEmpty());
+}
+
+/*!
+ This virtual function is called by QLocalServer when a new connection
+ is available. \a socketDescriptor is the native socket descriptor for
+ the accepted connection.
+
+ The base implementation creates a QLocalSocket, sets the socket descriptor
+ and then stores the QLocalSocket in an internal list of pending
+ connections. Finally newConnection() is emitted.
+
+ Reimplement this function to alter the server's behavior
+ when a connection is available.
+
+ \sa newConnection(), nextPendingConnection(),
+ QLocalSocket::setSocketDescriptor()
+ */
+void QLocalServer::incomingConnection(quintptr socketDescriptor)
+{
+ Q_D(QLocalServer);
+ QLocalSocket *socket = new QLocalSocket(this);
+ socket->setSocketDescriptor(socketDescriptor);
+ d->pendingConnections.enqueue(socket);
+ emit newConnection();
+}
+
+/*!
+ Returns true if the server is listening for incoming connections
+ otherwise false.
+
+ \sa listen(), close()
+ */
+bool QLocalServer::isListening() const
+{
+ Q_D(const QLocalServer);
+ return !(d->serverName.isEmpty());
+}
+
+/*!
+ Tells the server to listen for incoming connections on \a name.
+ If the server is currently listening then it will return false.
+ Return true on success otherwise false.
+
+ \a name can be a single name and QLocalServer will determine
+ the correct platform specific path. serverName() will return
+ the name that is passed into listen.
+
+ Usually you would just pass in a name like "foo", but on Unix this
+ could also be a path such as "/tmp/foo" and on Windows this could
+ be a pipe path such as "\\\\.\\pipe\\foo"
+
+ Note:
+ On Unix if the server crashes without closing listen will fail
+ with AddressInUseError. To create a new server the file should be removed.
+ On Windows two local servers can listen to the same pipe at the same
+ time, but any connections will go to one of the server.
+
+ \sa serverName(), isListening(), close()
+ */
+bool QLocalServer::listen(const QString &name)
+{
+ Q_D(QLocalServer);
+ if (isListening()) {
+ qWarning("QLocalServer::listen() called when already listening");
+ return false;
+ }
+
+ if (name.isEmpty()) {
+ d->error = QAbstractSocket::HostNotFoundError;
+ QString function = QLatin1String("QLocalServer::listen");
+ d->errorString = tr("%1: Name error").arg(function);
+ return false;
+ }
+
+ if (!d->listen(name)) {
+ d->serverName.clear();
+ d->fullServerName.clear();
+ return false;
+ }
+
+ d->serverName = name;
+ return true;
+}
+
+/*!
+ Returns the maximum number of pending accepted connections.
+ The default is 30.
+
+ \sa setMaxPendingConnections(), hasPendingConnections()
+ */
+int QLocalServer::maxPendingConnections() const
+{
+ Q_D(const QLocalServer);
+ return d->maxPendingConnections;
+}
+
+/*!
+ \fn void QLocalServer::newConnection()
+
+ This signal is emitted every time a new connection is available.
+
+ \sa hasPendingConnections(), nextPendingConnection()
+*/
+
+/*!
+ Returns the next pending connection as a connected QLocalSocket object.
+
+ The socket is created as a child of the server, which means that it is
+ automatically deleted when the QLocalServer object is destroyed. It is
+ still a good idea to delete the object explicitly when you are done with
+ it, to avoid wasting memory.
+
+ 0 is returned if this function is called when there are no pending
+ connections.
+
+ \sa hasPendingConnections(), newConnection(), incomingConnection()
+ */
+QLocalSocket *QLocalServer::nextPendingConnection()
+{
+ Q_D(QLocalServer);
+ if (d->pendingConnections.isEmpty())
+ return 0;
+ QLocalSocket *nextSocket = d->pendingConnections.dequeue();
+#ifndef QT_LOCALSOCKET_TCP
+#ifdef Q_OS_SYMBIAN
+ if(!d->socketNotifier)
+ return nextSocket;
+#endif
+ if (d->pendingConnections.size() <= d->maxPendingConnections)
+#ifndef Q_OS_WIN
+ d->socketNotifier->setEnabled(true);
+#else
+ d->connectionEventNotifier->setEnabled(true);
+#endif
+#endif
+ return nextSocket;
+}
+
+/*!
+ \since 4.5
+
+ Removes any server instance that might cause a call to listen() to fail
+ and returns true if successful; otherwise returns false.
+ This function is meant to recover from a crash, when the previous server
+ instance has not been cleaned up.
+
+ On Windows, this function does nothing; on Unix, it removes the socket file
+ given by \a name.
+
+ \warning Be careful to avoid removing sockets of running instances.
+*/
+bool QLocalServer::removeServer(const QString &name)
+{
+ return QLocalServerPrivate::removeServer(name);
+}
+
+/*!
+ Returns the server name if the server is listening for connections;
+ otherwise returns QString()
+
+ \sa listen(), fullServerName()
+ */
+QString QLocalServer::serverName() const
+{
+ Q_D(const QLocalServer);
+ return d->serverName;
+}
+
+/*!
+ Returns the full path that the server is listening on.
+
+ Note: This is platform specific
+
+ \sa listen(), serverName()
+ */
+QString QLocalServer::fullServerName() const
+{
+ Q_D(const QLocalServer);
+ return d->fullServerName;
+}
+
+/*!
+ Returns the type of error that occurred last or NoError.
+
+ \sa errorString()
+ */
+QAbstractSocket::SocketError QLocalServer::serverError() const
+{
+ Q_D(const QLocalServer);
+ return d->error;
+}
+
+/*!
+ Sets the maximum number of pending accepted connections to
+ \a numConnections. QLocalServer will accept no more than
+ \a numConnections incoming connections before nextPendingConnection()
+ is called.
+
+ Note: Even though QLocalServer will stop accepting new connections
+ after it has reached its maximum number of pending connections,
+ the operating system may still keep them in queue which will result
+ in clients signaling that it is connected.
+
+ \sa maxPendingConnections(), hasPendingConnections()
+ */
+void QLocalServer::setMaxPendingConnections(int numConnections)
+{
+ Q_D(QLocalServer);
+ d->maxPendingConnections = numConnections;
+}
+
+/*!
+ Waits for at most \a msec milliseconds or until an incoming connection
+ is available. Returns true if a connection is available; otherwise
+ returns false. If the operation timed out and \a timedOut is not 0,
+ *timedOut will be set to true.
+
+ This is a blocking function call. Its use is ill-advised in a
+ single-threaded GUI application, since the whole application will stop
+ responding until the function returns. waitForNewConnection() is mostly
+ useful when there is no event loop available.
+
+ The non-blocking alternative is to connect to the newConnection() signal.
+
+ If msec is -1, this function will not time out.
+
+ \sa hasPendingConnections(), nextPendingConnection()
+ */
+bool QLocalServer::waitForNewConnection(int msec, bool *timedOut)
+{
+ Q_D(QLocalServer);
+ if (timedOut)
+ *timedOut = false;
+
+ if (!isListening())
+ return false;
+
+ d->waitForNewConnection(msec, timedOut);
+
+ return !d->pendingConnections.isEmpty();
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qlocalserver.cpp"
+
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
new file mode 100644
index 0000000000..e8dc1c9b70
--- /dev/null
+++ b/src/network/socket/qlocalserver.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOCALSERVER_H
+#define QLOCALSERVER_H
+
+#include <QtNetwork/qabstractsocket.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_LOCALSERVER
+
+class QLocalSocket;
+class QLocalServerPrivate;
+
+class Q_NETWORK_EXPORT QLocalServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QLocalServer)
+
+Q_SIGNALS:
+ void newConnection();
+
+public:
+ QLocalServer(QObject *parent = 0);
+ ~QLocalServer();
+
+ void close();
+ QString errorString() const;
+ virtual bool hasPendingConnections() const;
+ bool isListening() const;
+ bool listen(const QString &name);
+ int maxPendingConnections() const;
+ virtual QLocalSocket *nextPendingConnection();
+ QString serverName() const;
+ QString fullServerName() const;
+ static bool removeServer(const QString &name);
+ QAbstractSocket::SocketError serverError() const;
+ void setMaxPendingConnections(int numConnections);
+ bool waitForNewConnection(int msec = 0, bool *timedOut = 0);
+
+protected:
+ virtual void incomingConnection(quintptr socketDescriptor);
+
+private:
+ Q_DISABLE_COPY(QLocalServer)
+ Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection())
+};
+
+#endif // QT_NO_LOCALSERVER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLOCALSERVER_H
+
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
new file mode 100644
index 0000000000..1ee5df2558
--- /dev/null
+++ b/src/network/socket/qlocalserver_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOCALSERVER_P_H
+#define QLOCALSERVER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLocalServer class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_LOCALSERVER
+
+#include "qlocalserver.h"
+#include "private/qobject_p.h"
+#include <qqueue.h>
+
+#if defined(QT_LOCALSOCKET_TCP)
+# include <qtcpserver.h>
+#elif defined(Q_OS_WIN)
+# include <qt_windows.h>
+# include <private/qwineventnotifier_p.h>
+#else
+# include <private/qabstractsocketengine_p.h>
+# include <qsocketnotifier.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QLocalServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QLocalServer)
+
+public:
+ QLocalServerPrivate() :
+#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN)
+ listenSocket(-1), socketNotifier(0),
+#endif
+ maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError)
+ {
+ }
+
+ void init();
+ bool listen(const QString &name);
+ static bool removeServer(const QString &name);
+ void closeServer();
+ void waitForNewConnection(int msec, bool *timedOut);
+ void _q_onNewConnection();
+
+#if defined(QT_LOCALSOCKET_TCP)
+
+ QTcpServer tcpServer;
+ QMap<quintptr, QTcpSocket*> socketMap;
+#elif defined(Q_OS_WIN)
+ struct Listener {
+ HANDLE handle;
+ OVERLAPPED overlapped;
+ bool connected;
+ };
+
+ void setError(const QString &function);
+ bool addListener();
+
+ QList<Listener> listeners;
+ HANDLE eventHandle;
+ QWinEventNotifier *connectionEventNotifier;
+#else
+ void setError(const QString &function);
+
+ int listenSocket;
+ QSocketNotifier *socketNotifier;
+#endif
+
+ QString serverName;
+ QString fullServerName;
+ int maxPendingConnections;
+ QQueue<QLocalSocket*> pendingConnections;
+ QString errorString;
+ QAbstractSocket::SocketError error;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LOCALSERVER
+
+#endif // QLOCALSERVER_P_H
+
diff --git a/src/network/socket/qlocalserver_tcp.cpp b/src/network/socket/qlocalserver_tcp.cpp
new file mode 100644
index 0000000000..aeda8635af
--- /dev/null
+++ b/src/network/socket/qlocalserver_tcp.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+
+#include <qhostaddress.h>
+#include <qsettings.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void QLocalServerPrivate::init()
+{
+ Q_Q(QLocalServer);
+ q->connect(&tcpServer, SIGNAL(newConnection()), SLOT(_q_onNewConnection()));
+}
+
+bool QLocalServerPrivate::listen(const QString &requestedServerName)
+{
+ if (!tcpServer.listen(QHostAddress::LocalHost))
+ return false;
+
+ const QLatin1String prefix("QLocalServer/");
+ if (requestedServerName.startsWith(prefix))
+ fullServerName = requestedServerName;
+ else
+ fullServerName = prefix + requestedServerName;
+
+ QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt"));
+ if (settings.contains(fullServerName)) {
+ qWarning("QLocalServer::listen: server name is already in use.");
+ tcpServer.close();
+ return false;
+ }
+
+ settings.setValue(fullServerName, tcpServer.serverPort());
+ return true;
+}
+
+void QLocalServerPrivate::closeServer()
+{
+ QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt"));
+ if (fullServerName == QLatin1String("QLocalServer"))
+ settings.setValue(fullServerName, QVariant());
+ else
+ settings.remove(fullServerName);
+ tcpServer.close();
+}
+
+void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
+{
+ if (pendingConnections.isEmpty())
+ tcpServer.waitForNewConnection(msec, timedOut);
+ else if (timedOut)
+ *timedOut = false;
+}
+
+void QLocalServerPrivate::_q_onNewConnection()
+{
+ Q_Q(QLocalServer);
+ QTcpSocket* tcpSocket = tcpServer.nextPendingConnection();
+ if (!tcpSocket) {
+ qWarning("QLocalServer: no pending connection");
+ return;
+ }
+
+ tcpSocket->setParent(q);
+ const quintptr socketDescriptor = tcpSocket->socketDescriptor();
+ q->incomingConnection(socketDescriptor);
+}
+
+bool QLocalServerPrivate::removeServer(const QString &name)
+{
+ const QLatin1String prefix("QLocalServer/");
+ QString serverName;
+ if (name.startsWith(prefix))
+ serverName = name;
+ else
+ serverName = prefix + name;
+
+ QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt"));
+ if (settings.contains(serverName))
+ settings.remove(serverName);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
new file mode 100644
index 0000000000..bc07fcf235
--- /dev/null
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+#include "qnet_unix_p.h"
+
+#ifndef QT_NO_LOCALSERVER
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <qdebug.h>
+#include <qdir.h>
+#include <qdatetime.h>
+
+#ifdef Q_OS_VXWORKS
+# include <selectLib.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+void QLocalServerPrivate::init()
+{
+}
+
+bool QLocalServerPrivate::removeServer(const QString &name)
+{
+ QString fileName;
+ if (name.startsWith(QLatin1Char('/'))) {
+ fileName = name;
+ } else {
+ fileName = QDir::cleanPath(QDir::tempPath());
+ fileName += QLatin1Char('/') + name;
+ }
+ if (QFile::exists(fileName))
+ return QFile::remove(fileName);
+ else
+ return true;
+}
+
+bool QLocalServerPrivate::listen(const QString &requestedServerName)
+{
+ Q_Q(QLocalServer);
+
+ // determine the full server path
+ if (requestedServerName.startsWith(QLatin1Char('/'))) {
+ fullServerName = requestedServerName;
+ } else {
+ fullServerName = QDir::cleanPath(QDir::tempPath());
+ fullServerName += QLatin1Char('/') + requestedServerName;
+ }
+ serverName = requestedServerName;
+
+ // create the unix socket
+ listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
+ if (-1 == listenSocket) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+
+ // Construct the unix address
+ struct ::sockaddr_un addr;
+ addr.sun_family = PF_UNIX;
+ if (sizeof(addr.sun_path) < (uint)fullServerName.toLatin1().size() + 1) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+ ::memcpy(addr.sun_path, fullServerName.toLatin1().data(),
+ fullServerName.toLatin1().size() + 1);
+
+#ifdef Q_OS_SYMBIAN
+ // In SYMBIAN OS it can currently happen that accept is called twice,
+ // once from waitForNewConnection and once via QSocketNotfier activity
+ //
+ // As an workaround, we set the socket to non blocking so possible
+ // subsequent call to accept will not block in any case
+ //
+ // This change can be removed once more generic fix to select thread
+ // synchronization problem is implemented.
+ int flags = fcntl(listenSocket, F_GETFL, 0);
+ if (-1 == flags
+ || -1 == (fcntl(listenSocket, F_SETFL, flags | O_NONBLOCK))) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+#endif
+
+ // bind
+ if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
+ setError(QLatin1String("QLocalServer::listen"));
+ // if address is in use already, just close the socket, but do not delete the file
+ if(errno == EADDRINUSE)
+ QT_CLOSE(listenSocket);
+ // otherwise, close the socket and delete the file
+ else
+ closeServer();
+ listenSocket = -1;
+ return false;
+ }
+
+ // listen for connections
+ if (-1 == qt_safe_listen(listenSocket, 50)) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ listenSocket = -1;
+ if (error != QAbstractSocket::AddressInUseError)
+ QFile::remove(fullServerName);
+ return false;
+ }
+ Q_ASSERT(!socketNotifier);
+ socketNotifier = new QSocketNotifier(listenSocket,
+ QSocketNotifier::Read, q);
+ q->connect(socketNotifier, SIGNAL(activated(int)),
+ q, SLOT(_q_onNewConnection()));
+ socketNotifier->setEnabled(maxPendingConnections > 0);
+ return true;
+}
+
+/*!
+ \internal
+
+ \sa QLocalServer::closeServer()
+ */
+void QLocalServerPrivate::closeServer()
+{
+ if (-1 != listenSocket)
+ QT_CLOSE(listenSocket);
+ listenSocket = -1;
+
+ if (socketNotifier) {
+ socketNotifier->setEnabled(false); // Otherwise, closed socket is checked before deleter runs
+ socketNotifier->deleteLater();
+ socketNotifier = 0;
+ }
+
+ if (!fullServerName.isEmpty())
+ QFile::remove(fullServerName);
+}
+
+/*!
+ \internal
+
+ We have received a notification that we can read on the listen socket.
+ Accept the new socket.
+ */
+void QLocalServerPrivate::_q_onNewConnection()
+{
+ Q_Q(QLocalServer);
+ if (-1 == listenSocket)
+ return;
+
+ ::sockaddr_un addr;
+ QT_SOCKLEN_T length = sizeof(sockaddr_un);
+ int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
+ if(-1 == connectedSocket) {
+ setError(QLatin1String("QLocalSocket::activated"));
+ closeServer();
+ } else {
+ socketNotifier->setEnabled(pendingConnections.size()
+ <= maxPendingConnections);
+ q->incomingConnection(connectedSocket);
+ }
+}
+
+void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
+{
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(listenSocket, &readfds);
+
+ timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ int result = -1;
+ result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);
+ if (-1 == result) {
+ setError(QLatin1String("QLocalServer::waitForNewConnection"));
+ closeServer();
+ }
+ if (result > 0)
+ _q_onNewConnection();
+ if (timedOut)
+ *timedOut = (result == 0);
+}
+
+void QLocalServerPrivate::setError(const QString &function)
+{
+ if (EAGAIN == errno)
+ return;
+
+ switch (errno) {
+ case EACCES:
+ errorString = QLocalServer::tr("%1: Permission denied").arg(function);
+ error = QAbstractSocket::SocketAccessError;
+ break;
+ case ELOOP:
+ case ENOENT:
+ case ENAMETOOLONG:
+ case EROFS:
+ case ENOTDIR:
+ errorString = QLocalServer::tr("%1: Name error").arg(function);
+ error = QAbstractSocket::HostNotFoundError;
+ break;
+ case EADDRINUSE:
+ errorString = QLocalServer::tr("%1: Address in use").arg(function);
+ error = QAbstractSocket::AddressInUseError;
+ break;
+
+ default:
+ errorString = QLocalServer::tr("%1: Unknown error %2")
+ .arg(function).arg(errno);
+ error = QAbstractSocket::UnknownSocketError;
+#if defined QLOCALSERVER_DEBUG
+ qWarning() << errorString << "fullServerName:" << fullServerName;
+#endif
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LOCALSERVER
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
new file mode 100644
index 0000000000..fb1015792f
--- /dev/null
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+
+#include <qdebug.h>
+
+// The buffer size need to be 0 otherwise data could be
+// lost if the socket that has written data closes the connection
+// before it is read. Pipewriter is used for write buffering.
+#define BUFSIZE 0
+
+// ###: This should be a property. Should replace the insane 50 on unix as well.
+#define SYSTEM_MAX_PENDING_SOCKETS 8
+
+QT_BEGIN_NAMESPACE
+
+bool QLocalServerPrivate::addListener()
+{
+ // The object must not change its address once the
+ // contained OVERLAPPED struct is passed to Windows.
+ listeners << Listener();
+ Listener &listener = listeners.last();
+
+ listener.handle = CreateNamedPipe(
+ (const wchar_t *)fullServerName.utf16(), // pipe name
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
+ PIPE_TYPE_BYTE | // byte type pipe
+ PIPE_READMODE_BYTE | // byte-read mode
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ BUFSIZE, // output buffer size
+ BUFSIZE, // input buffer size
+ 3000, // client time-out
+ NULL);
+
+ if (listener.handle == INVALID_HANDLE_VALUE) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ listeners.removeLast();
+ return false;
+ }
+
+ memset(&listener.overlapped, 0, sizeof(listener.overlapped));
+ listener.overlapped.hEvent = eventHandle;
+ if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
+ switch (GetLastError()) {
+ case ERROR_IO_PENDING:
+ listener.connected = false;
+ break;
+ case ERROR_PIPE_CONNECTED:
+ listener.connected = true;
+ SetEvent(eventHandle);
+ break;
+ default:
+ CloseHandle(listener.handle);
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ listeners.removeLast();
+ return false;
+ }
+ } else {
+ Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened");
+ SetEvent(eventHandle);
+ }
+ return true;
+}
+
+void QLocalServerPrivate::setError(const QString &function)
+{
+ int windowsError = GetLastError();
+ errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
+ error = QAbstractSocket::UnknownSocketError;
+}
+
+void QLocalServerPrivate::init()
+{
+}
+
+bool QLocalServerPrivate::removeServer(const QString &name)
+{
+ Q_UNUSED(name);
+ return true;
+}
+
+bool QLocalServerPrivate::listen(const QString &name)
+{
+ Q_Q(QLocalServer);
+
+ QString pipePath = QLatin1String("\\\\.\\pipe\\");
+ if (name.startsWith(pipePath))
+ fullServerName = name;
+ else
+ fullServerName = pipePath + name;
+
+ // Use only one event for all listeners of one socket.
+ // The idea is that listener events are rare, so polling all listeners once in a while is
+ // cheap compared to waiting for N additional events in each iteration of the main loop.
+ eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
+ connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
+ q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
+
+ for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
+ if (!addListener())
+ return false;
+ return true;
+}
+
+void QLocalServerPrivate::_q_onNewConnection()
+{
+ Q_Q(QLocalServer);
+ DWORD dummy;
+
+ // Reset first, otherwise we could reset an event which was asserted
+ // immediately after we checked the conn status.
+ ResetEvent(eventHandle);
+
+ // Testing shows that there is indeed absolutely no guarantee which listener gets
+ // a client connection first, so there is no way around polling all of them.
+ for (int i = 0; i < listeners.size(); ) {
+ HANDLE handle = listeners[i].handle;
+ if (listeners[i].connected
+ || GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE))
+ {
+ listeners.removeAt(i);
+
+ addListener();
+
+ if (pendingConnections.size() > maxPendingConnections)
+ connectionEventNotifier->setEnabled(false);
+
+ // Make this the last thing so connected slots can wreak the least havoc
+ q->incomingConnection((quintptr)handle);
+ } else {
+ if (GetLastError() != ERROR_IO_INCOMPLETE) {
+ q->close();
+ setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
+ return;
+ }
+
+ ++i;
+ }
+ }
+}
+
+void QLocalServerPrivate::closeServer()
+{
+ connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
+ connectionEventNotifier->deleteLater();
+ connectionEventNotifier = 0;
+ CloseHandle(eventHandle);
+ for (int i = 0; i < listeners.size(); ++i)
+ CloseHandle(listeners[i].handle);
+ listeners.clear();
+}
+
+void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
+{
+ Q_Q(QLocalServer);
+ if (!pendingConnections.isEmpty() || !q->isListening())
+ return;
+
+ DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
+ if (result == WAIT_TIMEOUT) {
+ if (timedOut)
+ *timedOut = true;
+ } else {
+ _q_onNewConnection();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp
new file mode 100644
index 0000000000..9a2b0ba3cd
--- /dev/null
+++ b/src/network/socket/qlocalsocket.cpp
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+
+#ifndef QT_NO_LOCALSOCKET
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QLocalSocket
+ \since 4.4
+
+ \brief The QLocalSocket class provides a local socket.
+
+ On Windows this is a named pipe and on Unix this is a local domain socket.
+
+ If an error occurs, socketError() returns the type of error, and
+ errorString() can be called to get a human readable description
+ of what happened.
+
+ Although QLocalSocket is designed for use with an event loop, it's possible
+ to use it without one. In that case, you must use waitForConnected(),
+ waitForReadyRead(), waitForBytesWritten(), and waitForDisconnected()
+ which blocks until the operation is complete or the timeout expires.
+
+ Note that this feature is not supported on versions of Windows earlier than
+ Windows XP.
+
+ \sa QLocalServer
+*/
+
+/*!
+ \fn void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
+
+ Attempts to make a connection to \a name.
+
+ The socket is opened in the given \a openMode and first enters ConnectingState.
+ It then attempts to connect to the address or addresses returned by the lookup.
+ Finally, if a connection is established, QLocalSocket enters ConnectedState
+ and emits connected().
+
+ At any point, the socket can emit error() to signal that an error occurred.
+
+ See also state(), serverName(), and waitForConnected().
+*/
+
+/*!
+ \fn void QLocalSocket::connected()
+
+ This signal is emitted after connectToServer() has been called and
+ a connection has been successfully established.
+
+ \sa connectToServer(), disconnected()
+*/
+
+/*!
+ \fn bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
+ LocalSocketState socketState, OpenMode openMode)
+
+ Initializes QLocalSocket with the native socket descriptor
+ \a socketDescriptor. Returns true if socketDescriptor is accepted
+ as a valid socket descriptor; otherwise returns false. The socket is
+ opened in the mode specified by \a openMode, and enters the socket state
+ specified by \a socketState.
+
+ \note It is not possible to initialize two local sockets with the same
+ native socket descriptor.
+
+ \sa socketDescriptor(), state(), openMode()
+*/
+
+/*!
+ \fn quintptr QLocalSocket::socketDescriptor() const
+
+ Returns the native socket descriptor of the QLocalSocket object if
+ this is available; otherwise returns -1.
+
+ The socket descriptor is not available when QLocalSocket
+ is in UnconnectedState.
+
+ \sa setSocketDescriptor()
+*/
+
+/*!
+ \fn qint64 QLocalSocket::readData(char *data, qint64 c)
+ \reimp
+*/
+
+/*!
+ \fn qint64 QLocalSocket::writeData(const char *data, qint64 c)
+ \reimp
+*/
+
+/*!
+ \fn void QLocalSocket::abort()
+
+ Aborts the current connection and resets the socket.
+ Unlike disconnectFromServer(), this function immediately closes the socket,
+ clearing any pending data in the write buffer.
+
+ \sa disconnectFromServer(), close()
+*/
+
+/*!
+ \fn qint64 QLocalSocket::bytesAvailable() const
+ \reimp
+*/
+
+/*!
+ \fn qint64 QLocalSocket::bytesToWrite() const
+ \reimp
+*/
+
+/*!
+ \fn bool QLocalSocket::canReadLine() const
+ \reimp
+*/
+
+/*!
+ \fn void QLocalSocket::close()
+ \reimp
+*/
+
+/*!
+ \fn bool QLocalSocket::waitForBytesWritten(int msecs)
+ \reimp
+*/
+
+/*!
+ \fn bool QLocalSocket::flush()
+
+ This function writes as much as possible from the internal write buffer
+ to the socket, without blocking. If any data was written, this function
+ returns true; otherwise false is returned.
+
+ Call this function if you need QLocalSocket to start sending buffered data
+ immediately. The number of bytes successfully written depends on the
+ operating system. In most cases, you do not need to call this function,
+ because QLocalSocket will start sending data automatically once control
+ goes back to the event loop. In the absence of an event loop, call
+ waitForBytesWritten() instead.
+
+ \sa write(), waitForBytesWritten()
+*/
+
+/*!
+ \fn void QLocalSocket::disconnectFromServer()
+
+ Attempts to close the socket. If there is pending data waiting to be
+ written, QLocalSocket will enter ClosingState and wait until all data
+ has been written. Eventually, it will enter UnconnectedState and emit
+ the disconnectedFromServer() signal.
+
+ \sa connectToServer()
+*/
+
+/*!
+ \fn QLocalSocket::LocalSocketError QLocalSocket::error() const
+
+ Returns the type of error that last occurred.
+
+ \sa state(), errorString()
+*/
+
+/*!
+ \fn bool QLocalSocket::isValid() const
+
+ Returns true if the socket is valid and ready for use; otherwise
+ returns false.
+
+ \note The socket's state must be ConnectedState before reading
+ and writing can occur.
+
+ \sa state(), connectToServer()
+*/
+
+/*!
+ \fn qint64 QLocalSocket::readBufferSize() const
+
+ Returns the size of the internal read buffer. This limits the amount of
+ data that the client can receive before you call read() or readAll().
+ A read buffer size of 0 (the default) means that the buffer has no size
+ limit, ensuring that no data is lost.
+
+ \sa setReadBufferSize(), read()
+*/
+
+/*!
+ \fn void QLocalSocket::setReadBufferSize(qint64 size)
+
+ Sets the size of QLocalSocket's internal read buffer to be \a size bytes.
+
+ If the buffer size is limited to a certain size, QLocalSocket won't
+ buffer more than this size of data. Exceptionally, a buffer size of 0
+ means that the read buffer is unlimited and all incoming data is buffered.
+ This is the default.
+
+ This option is useful if you only read the data at certain points in
+ time (e.g., in a real-time streaming application) or if you want to
+ protect your socket against receiving too much data, which may eventually
+ cause your application to run out of memory.
+
+ \sa readBufferSize(), read()
+*/
+
+/*!
+ \fn bool QLocalSocket::waitForConnected(int msecs)
+
+ Waits until the socket is connected, up to \a msecs milliseconds. If the
+ connection has been established, this function returns true; otherwise
+ it returns false. In the case where it returns false, you can call
+ error() to determine the cause of the error.
+
+ The following example waits up to one second for a connection
+ to be established:
+
+ \snippet doc/src/snippets/code/src_network_socket_qlocalsocket_unix.cpp 0
+
+ If \a msecs is -1, this function will not time out.
+
+ \sa connectToServer(), connected()
+*/
+
+/*!
+ \fn bool QLocalSocket::waitForDisconnected(int msecs)
+
+ Waits until the socket has disconnected, up to \a msecs
+ milliseconds. If the connection has been disconnected, this
+ function returns true; otherwise it returns false. In the case
+ where it returns false, you can call error() to determine
+ the cause of the error.
+
+ The following example waits up to one second for a connection
+ to be closed:
+
+ \snippet doc/src/snippets/code/src_network_socket_qlocalsocket_unix.cpp 1
+
+ If \a msecs is -1, this function will not time out.
+
+ \sa disconnectFromServer(), close()
+*/
+
+/*!
+ \fn bool QLocalSocket::waitForReadyRead(int msecs)
+
+ This function blocks until data is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if data is available for reading;
+ otherwise it returns false (if an error occurred or the
+ operation timed out).
+
+ \sa waitForBytesWritten()
+*/
+
+/*!
+ \fn void QLocalSocket::disconnected()
+
+ This signal is emitted when the socket has been disconnected.
+
+ \sa connectToServer(), disconnectFromServer(), abort(), connected()
+*/
+
+/*!
+ \fn void QLocalSocket::error(QLocalSocket::LocalSocketError socketError)
+
+ This signal is emitted after an error occurred. The \a socketError
+ parameter describes the type of error that occurred.
+
+ QLocalSocket::LocalSocketError is not a registered metatype, so for queued
+ connections, you will have to register it with Q_DECLARE_METATYPE() and
+ qRegisterMetaType().
+
+ \sa error(), errorString(), {Creating Custom Qt Types}
+*/
+
+/*!
+ \fn void QLocalSocket::stateChanged(QLocalSocket::LocalSocketState socketState)
+
+ This signal is emitted whenever QLocalSocket's state changes.
+ The \a socketState parameter is the new state.
+
+ QLocalSocket::SocketState is not a registered metatype, so for queued
+ connections, you will have to register it with Q_DECLARE_METATYPE() and
+ qRegisterMetaType().
+
+ \sa state(), {Creating Custom Qt Types}
+*/
+
+/*!
+ Creates a new local socket. The \a parent argument is passed to
+ QObject's constructor.
+ */
+QLocalSocket::QLocalSocket(QObject * parent)
+ : QIODevice(*new QLocalSocketPrivate, parent)
+{
+ Q_D(QLocalSocket);
+ d->init();
+}
+
+/*!
+ Destroys the socket, closing the connection if necessary.
+ */
+QLocalSocket::~QLocalSocket()
+{
+ close();
+#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+ Q_D(QLocalSocket);
+ d->unixSocket.setParent(0);
+#endif
+}
+
+/*!
+ Returns the name of the peer as specified by connectToServer(), or an
+ empty QString if connectToServer() has not been called or it failed.
+
+ \sa connectToServer(), fullServerName()
+
+ */
+QString QLocalSocket::serverName() const
+{
+ Q_D(const QLocalSocket);
+ return d->serverName;
+}
+
+/*!
+ Returns the server path that the socket is connected to.
+
+ \note The return value of this function is platform specific.
+
+ \sa connectToServer(), serverName()
+ */
+QString QLocalSocket::fullServerName() const
+{
+ Q_D(const QLocalSocket);
+ return d->fullServerName;
+}
+
+/*!
+ Returns the state of the socket.
+
+ \sa error()
+ */
+QLocalSocket::LocalSocketState QLocalSocket::state() const
+{
+ Q_D(const QLocalSocket);
+ return d->state;
+}
+
+/*! \reimp
+*/
+bool QLocalSocket::isSequential() const
+{
+ return true;
+}
+
+/*!
+ \enum QLocalSocket::LocalSocketError
+
+ The LocalServerError enumeration represents the errors that can occur.
+ The most recent error can be retrieved through a call to
+ \l QLocalSocket::error().
+
+ \value ConnectionRefusedError The connection was refused by
+ the peer (or timed out).
+ \value PeerClosedError The remote socket closed the connection.
+ Note that the client socket (i.e., this socket) will be closed
+ after the remote close notification has been sent.
+ \value ServerNotFoundError The local socket name was not found.
+ \value SocketAccessError The socket operation failed because the
+ application lacked the required privileges.
+ \value SocketResourceError The local system ran out of resources
+ (e.g., too many sockets).
+ \value SocketTimeoutError The socket operation timed out.
+ \value DatagramTooLargeError The datagram was larger than the operating
+ system's limit (which can be as low as 8192 bytes).
+ \value ConnectionError An error occurred with the connection.
+ \value UnsupportedSocketOperationError The requested socket operation
+ is not supported by the local operating system.
+ \value UnknownSocketError An unidentified error occurred.
+ */
+
+/*!
+ \enum QLocalSocket::LocalSocketState
+
+ This enum describes the different states in which a socket can be.
+
+ \sa QLocalSocket::state()
+
+ \value UnconnectedState The socket is not connected.
+ \value ConnectingState The socket has started establishing a connection.
+ \value ConnectedState A connection is established.
+ \value ClosingState The socket is about to close
+ (data may still be waiting to be written).
+ */
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketError error)
+{
+ switch (error) {
+ case QLocalSocket::ConnectionRefusedError:
+ debug << "QLocalSocket::ConnectionRefusedError";
+ break;
+ case QLocalSocket::PeerClosedError:
+ debug << "QLocalSocket::PeerClosedError";
+ break;
+ case QLocalSocket::ServerNotFoundError:
+ debug << "QLocalSocket::ServerNotFoundError";
+ break;
+ case QLocalSocket::SocketAccessError:
+ debug << "QLocalSocket::SocketAccessError";
+ break;
+ case QLocalSocket::SocketResourceError:
+ debug << "QLocalSocket::SocketResourceError";
+ break;
+ case QLocalSocket::SocketTimeoutError:
+ debug << "QLocalSocket::SocketTimeoutError";
+ break;
+ case QLocalSocket::DatagramTooLargeError:
+ debug << "QLocalSocket::DatagramTooLargeError";
+ break;
+ case QLocalSocket::ConnectionError:
+ debug << "QLocalSocket::ConnectionError";
+ break;
+ case QLocalSocket::UnsupportedSocketOperationError:
+ debug << "QLocalSocket::UnsupportedSocketOperationError";
+ break;
+ case QLocalSocket::UnknownSocketError:
+ debug << "QLocalSocket::UnknownSocketError";
+ break;
+ default:
+ debug << "QLocalSocket::SocketError(" << int(error) << ')';
+ break;
+ }
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketState state)
+{
+ switch (state) {
+ case QLocalSocket::UnconnectedState:
+ debug << "QLocalSocket::UnconnectedState";
+ break;
+ case QLocalSocket::ConnectingState:
+ debug << "QLocalSocket::ConnectingState";
+ break;
+ case QLocalSocket::ConnectedState:
+ debug << "QLocalSocket::ConnectedState";
+ break;
+ case QLocalSocket::ClosingState:
+ debug << "QLocalSocket::ClosingState";
+ break;
+ default:
+ debug << "QLocalSocket::SocketState(" << int(state) << ')';
+ break;
+ }
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif
+
+#include "moc_qlocalsocket.cpp"
diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h
new file mode 100644
index 0000000000..2f99b55a70
--- /dev/null
+++ b/src/network/socket/qlocalsocket.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOCALSOCKET_H
+#define QLOCALSOCKET_H
+
+#include <QtCore/qiodevice.h>
+#include <QtNetwork/qabstractsocket.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_LOCALSOCKET
+
+class QLocalSocketPrivate;
+
+class Q_NETWORK_EXPORT QLocalSocket : public QIODevice
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QLocalSocket)
+
+public:
+ enum LocalSocketError
+ {
+ ConnectionRefusedError = QAbstractSocket::ConnectionRefusedError,
+ PeerClosedError = QAbstractSocket::RemoteHostClosedError,
+ ServerNotFoundError = QAbstractSocket::HostNotFoundError,
+ SocketAccessError = QAbstractSocket::SocketAccessError,
+ SocketResourceError = QAbstractSocket::SocketResourceError,
+ SocketTimeoutError = QAbstractSocket::SocketTimeoutError,
+ DatagramTooLargeError = QAbstractSocket::DatagramTooLargeError,
+ ConnectionError = QAbstractSocket::NetworkError,
+ UnsupportedSocketOperationError = QAbstractSocket::UnsupportedSocketOperationError,
+ UnknownSocketError = QAbstractSocket::UnknownSocketError
+ };
+
+ enum LocalSocketState
+ {
+ UnconnectedState = QAbstractSocket::UnconnectedState,
+ ConnectingState = QAbstractSocket::ConnectingState,
+ ConnectedState = QAbstractSocket::ConnectedState,
+ ClosingState = QAbstractSocket::ClosingState
+ };
+
+ QLocalSocket(QObject *parent = 0);
+ ~QLocalSocket();
+
+ void connectToServer(const QString &name, OpenMode openMode = ReadWrite);
+ void disconnectFromServer();
+
+ QString serverName() const;
+ QString fullServerName() const;
+
+ void abort();
+ virtual bool isSequential() const;
+ virtual qint64 bytesAvailable() const;
+ virtual qint64 bytesToWrite() const;
+ virtual bool canReadLine() const;
+ virtual void close();
+ LocalSocketError error() const;
+ bool flush();
+ bool isValid() const;
+ qint64 readBufferSize() const;
+ void setReadBufferSize(qint64 size);
+
+ bool setSocketDescriptor(quintptr socketDescriptor,
+ LocalSocketState socketState = ConnectedState,
+ OpenMode openMode = ReadWrite);
+ quintptr socketDescriptor() const;
+
+ LocalSocketState state() const;
+ bool waitForBytesWritten(int msecs = 30000);
+ bool waitForConnected(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+ bool waitForReadyRead(int msecs = 30000);
+
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+ void error(QLocalSocket::LocalSocketError socketError);
+ void stateChanged(QLocalSocket::LocalSocketState socketState);
+
+protected:
+ virtual qint64 readData(char*, qint64);
+ virtual qint64 writeData(const char*, qint64);
+
+private:
+ Q_DISABLE_COPY(QLocalSocket)
+#if defined(QT_LOCALSOCKET_TCP)
+ Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QAbstractSocket::SocketState))
+ Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError))
+#elif defined(Q_OS_WIN)
+ Q_PRIVATE_SLOT(d_func(), void _q_notified())
+ Q_PRIVATE_SLOT(d_func(), void _q_canWrite())
+ Q_PRIVATE_SLOT(d_func(), void _q_pipeClosed())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitReadyRead())
+#else
+ Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QAbstractSocket::SocketState))
+ Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError))
+ Q_PRIVATE_SLOT(d_func(), void _q_connectToSocket())
+ Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt())
+#endif
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketError);
+Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketState);
+#endif
+
+#endif // QT_NO_LOCALSOCKET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLOCALSOCKET_H
diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h
new file mode 100644
index 0000000000..09e50f512f
--- /dev/null
+++ b/src/network/socket/qlocalsocket_p.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOCALSOCKET_P_H
+#define QLOCALSOCKET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLocalSocket class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_LOCALSOCKET
+
+#include "qlocalsocket.h"
+#include "private/qiodevice_p.h"
+
+#include <qtimer.h>
+
+#if defined(QT_LOCALSOCKET_TCP)
+# include "qtcpsocket.h"
+#elif defined(Q_OS_WIN)
+# include "private/qwindowspipewriter_p.h"
+# include "private/qringbuffer_p.h"
+# include <private/qwineventnotifier_p.h>
+#else
+# include "private/qabstractsocketengine_p.h"
+# include <qtcpsocket.h>
+# include <qsocketnotifier.h>
+# include <errno.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(Q_OS_WIN) || defined(QT_LOCALSOCKET_TCP)
+class QLocalUnixSocket : public QTcpSocket
+{
+
+public:
+ QLocalUnixSocket() : QTcpSocket()
+ {
+ };
+
+ inline void setSocketState(QAbstractSocket::SocketState state)
+ {
+ QTcpSocket::setSocketState(state);
+ };
+
+ inline void setErrorString(const QString &string)
+ {
+ QTcpSocket::setErrorString(string);
+ }
+
+ inline void setSocketError(QAbstractSocket::SocketError error)
+ {
+ QTcpSocket::setSocketError(error);
+ }
+
+ inline qint64 readData(char *data, qint64 maxSize)
+ {
+ return QTcpSocket::readData(data, maxSize);
+ }
+
+ inline qint64 writeData(const char *data, qint64 maxSize)
+ {
+ return QTcpSocket::writeData(data, maxSize);
+ }
+};
+#endif //#if !defined(Q_OS_WIN) || defined(QT_LOCALSOCKET_TCP)
+
+class QLocalSocketPrivate : public QIODevicePrivate
+{
+ Q_DECLARE_PUBLIC(QLocalSocket)
+
+public:
+ QLocalSocketPrivate();
+ void init();
+
+#if defined(QT_LOCALSOCKET_TCP)
+ QLocalUnixSocket* tcpSocket;
+ bool ownsTcpSocket;
+ void setSocket(QLocalUnixSocket*);
+ QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const;
+ void errorOccurred(QLocalSocket::LocalSocketError, const QString &function);
+ void _q_stateChanged(QAbstractSocket::SocketState newState);
+ void _q_error(QAbstractSocket::SocketError newError);
+#elif defined(Q_OS_WIN)
+ ~QLocalSocketPrivate();
+ void destroyPipeHandles();
+ void setErrorString(const QString &function);
+ void _q_notified();
+ void _q_canWrite();
+ void _q_pipeClosed();
+ void _q_emitReadyRead();
+ DWORD checkPipeState();
+ void startAsyncRead();
+ bool completeAsyncRead();
+ void checkReadyRead();
+ HANDLE handle;
+ OVERLAPPED overlapped;
+ QWindowsPipeWriter *pipeWriter;
+ qint64 readBufferMaxSize;
+ QRingBuffer readBuffer;
+ int actualReadBufferSize;
+ QWinEventNotifier *dataReadNotifier;
+ QLocalSocket::LocalSocketError error;
+ bool readSequenceStarted;
+ bool pendingReadyRead;
+ bool pipeClosed;
+ static const qint64 initialReadBufferSize = 4096;
+#else
+ QLocalUnixSocket unixSocket;
+ QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const;
+ void errorOccurred(QLocalSocket::LocalSocketError, const QString &function);
+ void _q_stateChanged(QAbstractSocket::SocketState newState);
+ void _q_error(QAbstractSocket::SocketError newError);
+ void _q_connectToSocket();
+ void _q_abortConnectionAttempt();
+ void cancelDelayedConnect();
+ QSocketNotifier *delayConnect;
+ QTimer *connectTimer;
+ int connectingSocket;
+ QString connectingName;
+ QIODevice::OpenMode connectingOpenMode;
+#endif
+
+ QString serverName;
+ QString fullServerName;
+ QLocalSocket::LocalSocketState state;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LOCALSOCKET
+
+#endif // QLOCALSOCKET_P_H
+
diff --git a/src/network/socket/qlocalsocket_tcp.cpp b/src/network/socket/qlocalsocket_tcp.cpp
new file mode 100644
index 0000000000..182d64aeb3
--- /dev/null
+++ b/src/network/socket/qlocalsocket_tcp.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+#include "qlocalserver.h"
+
+#include <qhostaddress.h>
+#include <qsettings.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
+ tcpSocket(0),
+ ownsTcpSocket(true),
+ state(QLocalSocket::UnconnectedState)
+{
+}
+
+void QLocalSocketPrivate::init()
+{
+ setSocket(new QLocalUnixSocket);
+}
+
+void QLocalSocketPrivate::setSocket(QLocalUnixSocket* socket)
+{
+ if (ownsTcpSocket)
+ delete tcpSocket;
+ ownsTcpSocket = false;
+ tcpSocket = socket;
+
+ Q_Q(QLocalSocket);
+ // QIODevice signals
+ q->connect(tcpSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
+ q->connect(tcpSocket, SIGNAL(bytesWritten(qint64)),
+ q, SIGNAL(bytesWritten(qint64)));
+ q->connect(tcpSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
+ // QAbstractSocket signals
+ q->connect(tcpSocket, SIGNAL(connected()), q, SIGNAL(connected()));
+ q->connect(tcpSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
+ q->connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
+ q->connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ q, SLOT(_q_error(QAbstractSocket::SocketError)));
+ q->connect(tcpSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
+ tcpSocket->setParent(q);
+}
+
+void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError)
+{
+ Q_Q(QLocalSocket);
+ QString function = QLatin1String("QLocalSocket");
+ QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
+ QString errorString = generateErrorString(error, function);
+ q->setErrorString(errorString);
+ emit q->error(error);
+}
+
+void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)
+{
+ Q_Q(QLocalSocket);
+ QLocalSocket::LocalSocketState currentState = state;
+ switch(newState) {
+ case QAbstractSocket::UnconnectedState:
+ state = QLocalSocket::UnconnectedState;
+ serverName.clear();
+ fullServerName.clear();
+ break;
+ case QAbstractSocket::ConnectingState:
+ state = QLocalSocket::ConnectingState;
+ break;
+ case QAbstractSocket::ConnectedState:
+ state = QLocalSocket::ConnectedState;
+ break;
+ case QAbstractSocket::ClosingState:
+ state = QLocalSocket::ClosingState;
+ break;
+ default:
+#if defined QLOCALSOCKET_DEBUG
+ qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;
+#endif
+ return;
+ }
+ if (currentState != state)
+ emit q->stateChanged(state);
+}
+
+QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const
+{
+ QString errorString;
+ switch (error) {
+ case QLocalSocket::ConnectionRefusedError:
+ errorString = QLocalSocket::tr("%1: Connection refused").arg(function);
+ break;
+ case QLocalSocket::PeerClosedError:
+ errorString = QLocalSocket::tr("%1: Remote closed").arg(function);
+ break;
+ case QLocalSocket::ServerNotFoundError:
+ errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
+ break;
+ case QLocalSocket::SocketAccessError:
+ errorString = QLocalSocket::tr("%1: Socket access error").arg(function);
+ break;
+ case QLocalSocket::SocketResourceError:
+ errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);
+ break;
+ case QLocalSocket::SocketTimeoutError:
+ errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);
+ break;
+ case QLocalSocket::DatagramTooLargeError:
+ errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);
+ break;
+ case QLocalSocket::ConnectionError:
+ errorString = QLocalSocket::tr("%1: Connection error").arg(function);
+ break;
+ case QLocalSocket::UnsupportedSocketOperationError:
+ errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);
+ break;
+ case QLocalSocket::UnknownSocketError:
+ default:
+ errorString = QLocalSocket::tr("%1: Unknown error").arg(function);
+ }
+ return errorString;
+}
+
+void QLocalSocketPrivate::errorOccurred(QLocalSocket::LocalSocketError error, const QString &function)
+{
+ Q_Q(QLocalSocket);
+ switch (error) {
+ case QLocalSocket::ConnectionRefusedError:
+ tcpSocket->setSocketError(QAbstractSocket::ConnectionRefusedError);
+ break;
+ case QLocalSocket::PeerClosedError:
+ tcpSocket->setSocketError(QAbstractSocket::RemoteHostClosedError);
+ break;
+ case QLocalSocket::ServerNotFoundError:
+ tcpSocket->setSocketError(QAbstractSocket::HostNotFoundError);
+ break;
+ case QLocalSocket::SocketAccessError:
+ tcpSocket->setSocketError(QAbstractSocket::SocketAccessError);
+ break;
+ case QLocalSocket::SocketResourceError:
+ tcpSocket->setSocketError(QAbstractSocket::SocketResourceError);
+ break;
+ case QLocalSocket::SocketTimeoutError:
+ tcpSocket->setSocketError(QAbstractSocket::SocketTimeoutError);
+ break;
+ case QLocalSocket::DatagramTooLargeError:
+ tcpSocket->setSocketError(QAbstractSocket::DatagramTooLargeError);
+ break;
+ case QLocalSocket::ConnectionError:
+ tcpSocket->setSocketError(QAbstractSocket::NetworkError);
+ break;
+ case QLocalSocket::UnsupportedSocketOperationError:
+ tcpSocket->setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
+ break;
+ case QLocalSocket::UnknownSocketError:
+ default:
+ tcpSocket->setSocketError(QAbstractSocket::UnknownSocketError);
+ }
+
+ QString errorString = generateErrorString(error, function);
+ q->setErrorString(errorString);
+ emit q->error(error);
+
+ // errors cause a disconnect
+ tcpSocket->setSocketState(QAbstractSocket::UnconnectedState);
+ bool stateChanged = (state != QLocalSocket::UnconnectedState);
+ state = QLocalSocket::UnconnectedState;
+ q->close();
+ if (stateChanged)
+ q->emit stateChanged(state);
+}
+
+void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ if (state() == ConnectedState
+ || state() == ConnectingState)
+ return;
+
+ d->errorString.clear();
+ d->state = ConnectingState;
+ emit stateChanged(d->state);
+
+ if (name.isEmpty()) {
+ d->errorOccurred(ServerNotFoundError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+
+ d->serverName = name;
+ const QLatin1String prefix("QLocalServer/");
+ if (name.startsWith(prefix))
+ d->fullServerName = name;
+ else
+ d->fullServerName = prefix + name;
+
+ QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt"));
+ bool ok;
+ const quint16 port = settings.value(d->fullServerName).toUInt(&ok);
+ if (!ok) {
+ d->errorOccurred(ServerNotFoundError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+ d->tcpSocket->connectToHost(QHostAddress::LocalHost, port, openMode);
+ QIODevice::open(openMode);
+}
+
+bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
+ LocalSocketState socketState, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;
+ switch (socketState) {
+ case ConnectingState:
+ newSocketState = QAbstractSocket::ConnectingState;
+ break;
+ case ConnectedState:
+ newSocketState = QAbstractSocket::ConnectedState;
+ break;
+ case ClosingState:
+ newSocketState = QAbstractSocket::ClosingState;
+ break;
+ case UnconnectedState:
+ newSocketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ QIODevice::open(openMode);
+ d->state = socketState;
+
+ // Is our parent a localServer? Then it wants us to use its remote socket.
+ QLocalServer* localServer = qobject_cast<QLocalServer*>( parent() );
+ if (localServer) {
+ foreach (QObject* child, localServer->children()) {
+ QTcpSocket* childTcpSocket = qobject_cast<QTcpSocket*>(child);
+ if (childTcpSocket && childTcpSocket->socketDescriptor() == socketDescriptor) {
+ d->setSocket( static_cast<QLocalUnixSocket*>(childTcpSocket) );
+ return true;
+ }
+ }
+ }
+
+ // We couldn't find the socket in the children list of our server.
+ // So it might be that the user wants to set a socket descriptor.
+ return d->tcpSocket->setSocketDescriptor(socketDescriptor,
+ newSocketState, openMode);
+}
+
+quintptr QLocalSocket::socketDescriptor() const
+{
+ Q_D(const QLocalSocket);
+ return d->tcpSocket->socketDescriptor();
+}
+
+qint64 QLocalSocket::readData(char *data, qint64 c)
+{
+ Q_D(QLocalSocket);
+ return d->tcpSocket->readData(data, c);
+}
+
+qint64 QLocalSocket::writeData(const char *data, qint64 c)
+{
+ Q_D(QLocalSocket);
+ return d->tcpSocket->writeData(data, c);
+}
+
+void QLocalSocket::abort()
+{
+ Q_D(QLocalSocket);
+ d->tcpSocket->abort();
+}
+
+qint64 QLocalSocket::bytesAvailable() const
+{
+ Q_D(const QLocalSocket);
+ return QIODevice::bytesAvailable() + d->tcpSocket->bytesAvailable();
+}
+
+qint64 QLocalSocket::bytesToWrite() const
+{
+ Q_D(const QLocalSocket);
+ return d->tcpSocket->bytesToWrite();
+}
+
+bool QLocalSocket::canReadLine() const
+{
+ Q_D(const QLocalSocket);
+ return QIODevice::canReadLine() || d->tcpSocket->canReadLine();
+}
+
+void QLocalSocket::close()
+{
+ Q_D(QLocalSocket);
+ d->tcpSocket->close();
+ d->serverName.clear();
+ d->fullServerName.clear();
+ QIODevice::close();
+}
+
+bool QLocalSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(QLocalSocket);
+ return d->tcpSocket->waitForBytesWritten(msecs);
+}
+
+bool QLocalSocket::flush()
+{
+ Q_D(QLocalSocket);
+ return d->tcpSocket->flush();
+}
+
+void QLocalSocket::disconnectFromServer()
+{
+ Q_D(QLocalSocket);
+ d->tcpSocket->disconnectFromHost();
+}
+
+QLocalSocket::LocalSocketError QLocalSocket::error() const
+{
+ Q_D(const QLocalSocket);
+ switch (d->tcpSocket->error()) {
+ case QAbstractSocket::ConnectionRefusedError:
+ return QLocalSocket::ConnectionRefusedError;
+ case QAbstractSocket::RemoteHostClosedError:
+ return QLocalSocket::PeerClosedError;
+ case QAbstractSocket::HostNotFoundError:
+ return QLocalSocket::ServerNotFoundError;
+ case QAbstractSocket::SocketAccessError:
+ return QLocalSocket::SocketAccessError;
+ case QAbstractSocket::SocketResourceError:
+ return QLocalSocket::SocketResourceError;
+ case QAbstractSocket::SocketTimeoutError:
+ return QLocalSocket::SocketTimeoutError;
+ case QAbstractSocket::DatagramTooLargeError:
+ return QLocalSocket::DatagramTooLargeError;
+ case QAbstractSocket::NetworkError:
+ return QLocalSocket::ConnectionError;
+ case QAbstractSocket::UnsupportedSocketOperationError:
+ return QLocalSocket::UnsupportedSocketOperationError;
+ case QAbstractSocket::UnknownSocketError:
+ return QLocalSocket::UnknownSocketError;
+ default:
+#if defined QLOCALSOCKET_DEBUG
+ qWarning() << "QLocalSocket error not handled:" << d->tcpSocket->error();
+#endif
+ break;
+ }
+ return UnknownSocketError;
+}
+
+bool QLocalSocket::isValid() const
+{
+ Q_D(const QLocalSocket);
+ return d->tcpSocket->isValid();
+}
+
+qint64 QLocalSocket::readBufferSize() const
+{
+ Q_D(const QLocalSocket);
+ return d->tcpSocket->readBufferSize();
+}
+
+void QLocalSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QLocalSocket);
+ d->tcpSocket->setReadBufferSize(size);
+}
+
+bool QLocalSocket::waitForConnected(int msec)
+{
+ Q_D(QLocalSocket);
+ if (state() != ConnectingState)
+ return (state() == ConnectedState);
+
+ return d->tcpSocket->waitForConnected(msec);
+}
+
+bool QLocalSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QLocalSocket);
+ if (state() == UnconnectedState) {
+ qWarning() << "QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState";
+ return false;
+ }
+ return (d->tcpSocket->waitForDisconnected(msecs));
+}
+
+bool QLocalSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QLocalSocket);
+ if (state() == QLocalSocket::UnconnectedState)
+ return false;
+ return (d->tcpSocket->waitForReadyRead(msecs));
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
new file mode 100644
index 0000000000..da85d917e4
--- /dev/null
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -0,0 +1,581 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+#include "qnet_unix_p.h"
+
+#ifndef QT_NO_LOCALSOCKET
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <qdir.h>
+#include <qdebug.h>
+#include <qelapsedtimer.h>
+
+#ifdef Q_OS_VXWORKS
+# include <selectLib.h>
+#endif
+
+#define QT_CONNECT_TIMEOUT 30000
+
+QT_BEGIN_NAMESPACE
+
+QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
+ delayConnect(0),
+ connectTimer(0),
+ connectingSocket(-1),
+ connectingOpenMode(0),
+ state(QLocalSocket::UnconnectedState)
+{
+}
+
+void QLocalSocketPrivate::init()
+{
+ Q_Q(QLocalSocket);
+ // QIODevice signals
+ q->connect(&unixSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
+ q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),
+ q, SIGNAL(bytesWritten(qint64)));
+ q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
+ // QAbstractSocket signals
+ q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected()));
+ q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
+ q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
+ q->connect(&unixSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ q, SLOT(_q_error(QAbstractSocket::SocketError)));
+ q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
+ unixSocket.setParent(q);
+}
+
+void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError)
+{
+ Q_Q(QLocalSocket);
+ QString function = QLatin1String("QLocalSocket");
+ QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
+ QString errorString = generateErrorString(error, function);
+ q->setErrorString(errorString);
+ emit q->error(error);
+}
+
+void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)
+{
+ Q_Q(QLocalSocket);
+ QLocalSocket::LocalSocketState currentState = state;
+ switch(newState) {
+ case QAbstractSocket::UnconnectedState:
+ state = QLocalSocket::UnconnectedState;
+ serverName.clear();
+ fullServerName.clear();
+ break;
+ case QAbstractSocket::ConnectingState:
+ state = QLocalSocket::ConnectingState;
+ break;
+ case QAbstractSocket::ConnectedState:
+ state = QLocalSocket::ConnectedState;
+ break;
+ case QAbstractSocket::ClosingState:
+ state = QLocalSocket::ClosingState;
+ break;
+ default:
+#if defined QLOCALSOCKET_DEBUG
+ qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;
+#endif
+ return;
+ }
+ if (currentState != state)
+ emit q->stateChanged(state);
+}
+
+QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const
+{
+ QString errorString;
+ switch (error) {
+ case QLocalSocket::ConnectionRefusedError:
+ errorString = QLocalSocket::tr("%1: Connection refused").arg(function);
+ break;
+ case QLocalSocket::PeerClosedError:
+ errorString = QLocalSocket::tr("%1: Remote closed").arg(function);
+ break;
+ case QLocalSocket::ServerNotFoundError:
+ errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
+ break;
+ case QLocalSocket::SocketAccessError:
+ errorString = QLocalSocket::tr("%1: Socket access error").arg(function);
+ break;
+ case QLocalSocket::SocketResourceError:
+ errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);
+ break;
+ case QLocalSocket::SocketTimeoutError:
+ errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);
+ break;
+ case QLocalSocket::DatagramTooLargeError:
+ errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);
+ break;
+ case QLocalSocket::ConnectionError:
+ errorString = QLocalSocket::tr("%1: Connection error").arg(function);
+ break;
+ case QLocalSocket::UnsupportedSocketOperationError:
+ errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);
+ break;
+ case QLocalSocket::UnknownSocketError:
+ default:
+ errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(errno);
+ }
+ return errorString;
+}
+
+void QLocalSocketPrivate::errorOccurred(QLocalSocket::LocalSocketError error, const QString &function)
+{
+ Q_Q(QLocalSocket);
+ switch (error) {
+ case QLocalSocket::ConnectionRefusedError:
+ unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError);
+ break;
+ case QLocalSocket::PeerClosedError:
+ unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError);
+ break;
+ case QLocalSocket::ServerNotFoundError:
+ unixSocket.setSocketError(QAbstractSocket::HostNotFoundError);
+ break;
+ case QLocalSocket::SocketAccessError:
+ unixSocket.setSocketError(QAbstractSocket::SocketAccessError);
+ break;
+ case QLocalSocket::SocketResourceError:
+ unixSocket.setSocketError(QAbstractSocket::SocketResourceError);
+ break;
+ case QLocalSocket::SocketTimeoutError:
+ unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError);
+ break;
+ case QLocalSocket::DatagramTooLargeError:
+ unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError);
+ break;
+ case QLocalSocket::ConnectionError:
+ unixSocket.setSocketError(QAbstractSocket::NetworkError);
+ break;
+ case QLocalSocket::UnsupportedSocketOperationError:
+ unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
+ break;
+ case QLocalSocket::UnknownSocketError:
+ default:
+ unixSocket.setSocketError(QAbstractSocket::UnknownSocketError);
+ }
+
+ QString errorString = generateErrorString(error, function);
+ q->setErrorString(errorString);
+ emit q->error(error);
+
+ // errors cause a disconnect
+ unixSocket.setSocketState(QAbstractSocket::UnconnectedState);
+ bool stateChanged = (state != QLocalSocket::UnconnectedState);
+ state = QLocalSocket::UnconnectedState;
+ q->close();
+ if (stateChanged)
+ q->emit stateChanged(state);
+}
+
+void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ if (state() == ConnectedState
+ || state() == ConnectingState)
+ return;
+
+ d->errorString.clear();
+ d->unixSocket.setSocketState(QAbstractSocket::ConnectingState);
+ d->state = ConnectingState;
+ emit stateChanged(d->state);
+
+ if (name.isEmpty()) {
+ d->errorOccurred(ServerNotFoundError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+
+ // create the socket
+ if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0))) {
+ d->errorOccurred(UnsupportedSocketOperationError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+#ifndef Q_OS_SYMBIAN
+ // set non blocking so we can try to connect and it wont wait
+ int flags = fcntl(d->connectingSocket, F_GETFL, 0);
+ if (-1 == flags
+ || -1 == (fcntl(d->connectingSocket, F_SETFL, flags | O_NONBLOCK))) {
+ d->errorOccurred(UnknownSocketError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+#endif
+
+ // _q_connectToSocket does the actual connecting
+ d->connectingName = name;
+ d->connectingOpenMode = openMode;
+ d->_q_connectToSocket();
+}
+
+/*!
+ \internal
+
+ Tries to connect connectingName and connectingOpenMode
+
+ \sa connectToServer() waitForConnected()
+ */
+void QLocalSocketPrivate::_q_connectToSocket()
+{
+ Q_Q(QLocalSocket);
+ QString connectingPathName;
+
+ // determine the full server path
+ if (connectingName.startsWith(QLatin1Char('/'))) {
+ connectingPathName = connectingName;
+ } else {
+ connectingPathName = QDir::tempPath();
+ connectingPathName += QLatin1Char('/') + connectingName;
+ }
+
+ struct sockaddr_un name;
+ name.sun_family = PF_UNIX;
+ if (sizeof(name.sun_path) < (uint)connectingPathName.toLatin1().size() + 1) {
+ QString function = QLatin1String("QLocalSocket::connectToServer");
+ errorOccurred(QLocalSocket::ServerNotFoundError, function);
+ return;
+ }
+ ::memcpy(name.sun_path, connectingPathName.toLatin1().data(),
+ connectingPathName.toLatin1().size() + 1);
+ if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
+ QString function = QLatin1String("QLocalSocket::connectToServer");
+ switch (errno)
+ {
+ case EINVAL:
+ case ECONNREFUSED:
+ errorOccurred(QLocalSocket::ConnectionRefusedError, function);
+ break;
+ case ENOENT:
+ errorOccurred(QLocalSocket::ServerNotFoundError, function);
+ break;
+ case EACCES:
+ case EPERM:
+ errorOccurred(QLocalSocket::SocketAccessError, function);
+ break;
+ case ETIMEDOUT:
+ errorOccurred(QLocalSocket::SocketTimeoutError, function);
+ break;
+ case EAGAIN:
+ // Try again later, all of the sockets listening are full
+ if (!delayConnect) {
+ delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);
+ q->connect(delayConnect, SIGNAL(activated(int)), q, SLOT(_q_connectToSocket()));
+ }
+ if (!connectTimer) {
+ connectTimer = new QTimer(q);
+ q->connect(connectTimer, SIGNAL(timeout()),
+ q, SLOT(_q_abortConnectionAttempt()),
+ Qt::DirectConnection);
+ connectTimer->start(QT_CONNECT_TIMEOUT);
+ }
+ delayConnect->setEnabled(true);
+ break;
+ default:
+ errorOccurred(QLocalSocket::UnknownSocketError, function);
+ }
+ return;
+ }
+
+ // connected!
+ cancelDelayedConnect();
+
+ serverName = connectingName;
+ fullServerName = connectingPathName;
+ if (unixSocket.setSocketDescriptor(connectingSocket,
+ QAbstractSocket::ConnectedState, connectingOpenMode)) {
+ q->QIODevice::open(connectingOpenMode);
+ q->emit connected();
+ } else {
+ QString function = QLatin1String("QLocalSocket::connectToServer");
+ errorOccurred(QLocalSocket::UnknownSocketError, function);
+ }
+ connectingSocket = -1;
+ connectingName.clear();
+ connectingOpenMode = 0;
+}
+
+bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
+ LocalSocketState socketState, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;
+ switch (socketState) {
+ case ConnectingState:
+ newSocketState = QAbstractSocket::ConnectingState;
+ break;
+ case ConnectedState:
+ newSocketState = QAbstractSocket::ConnectedState;
+ break;
+ case ClosingState:
+ newSocketState = QAbstractSocket::ClosingState;
+ break;
+ case UnconnectedState:
+ newSocketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ QIODevice::open(openMode);
+ d->state = socketState;
+ return d->unixSocket.setSocketDescriptor(socketDescriptor,
+ newSocketState, openMode);
+}
+
+void QLocalSocketPrivate::_q_abortConnectionAttempt()
+{
+ Q_Q(QLocalSocket);
+ q->close();
+}
+
+void QLocalSocketPrivate::cancelDelayedConnect()
+{
+ if (delayConnect) {
+ delayConnect->setEnabled(false);
+ delete delayConnect;
+ delayConnect = 0;
+ connectTimer->stop();
+ delete connectTimer;
+ connectTimer = 0;
+ }
+}
+
+quintptr QLocalSocket::socketDescriptor() const
+{
+ Q_D(const QLocalSocket);
+ return d->unixSocket.socketDescriptor();
+}
+
+qint64 QLocalSocket::readData(char *data, qint64 c)
+{
+ Q_D(QLocalSocket);
+ return d->unixSocket.readData(data, c);
+}
+
+qint64 QLocalSocket::writeData(const char *data, qint64 c)
+{
+ Q_D(QLocalSocket);
+ return d->unixSocket.writeData(data, c);
+}
+
+void QLocalSocket::abort()
+{
+ Q_D(QLocalSocket);
+ d->unixSocket.abort();
+}
+
+qint64 QLocalSocket::bytesAvailable() const
+{
+ Q_D(const QLocalSocket);
+ return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable();
+}
+
+qint64 QLocalSocket::bytesToWrite() const
+{
+ Q_D(const QLocalSocket);
+ return d->unixSocket.bytesToWrite();
+}
+
+bool QLocalSocket::canReadLine() const
+{
+ Q_D(const QLocalSocket);
+ return QIODevice::canReadLine() || d->unixSocket.canReadLine();
+}
+
+void QLocalSocket::close()
+{
+ Q_D(QLocalSocket);
+ d->unixSocket.close();
+ d->cancelDelayedConnect();
+ if (d->connectingSocket != -1)
+ ::close(d->connectingSocket);
+ d->connectingSocket = -1;
+ d->connectingName.clear();
+ d->connectingOpenMode = 0;
+ d->serverName.clear();
+ d->fullServerName.clear();
+ QIODevice::close();
+}
+
+bool QLocalSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(QLocalSocket);
+ return d->unixSocket.waitForBytesWritten(msecs);
+}
+
+bool QLocalSocket::flush()
+{
+ Q_D(QLocalSocket);
+ return d->unixSocket.flush();
+}
+
+void QLocalSocket::disconnectFromServer()
+{
+ Q_D(QLocalSocket);
+ d->unixSocket.disconnectFromHost();
+}
+
+QLocalSocket::LocalSocketError QLocalSocket::error() const
+{
+ Q_D(const QLocalSocket);
+ switch (d->unixSocket.error()) {
+ case QAbstractSocket::ConnectionRefusedError:
+ return QLocalSocket::ConnectionRefusedError;
+ case QAbstractSocket::RemoteHostClosedError:
+ return QLocalSocket::PeerClosedError;
+ case QAbstractSocket::HostNotFoundError:
+ return QLocalSocket::ServerNotFoundError;
+ case QAbstractSocket::SocketAccessError:
+ return QLocalSocket::SocketAccessError;
+ case QAbstractSocket::SocketResourceError:
+ return QLocalSocket::SocketResourceError;
+ case QAbstractSocket::SocketTimeoutError:
+ return QLocalSocket::SocketTimeoutError;
+ case QAbstractSocket::DatagramTooLargeError:
+ return QLocalSocket::DatagramTooLargeError;
+ case QAbstractSocket::NetworkError:
+ return QLocalSocket::ConnectionError;
+ case QAbstractSocket::UnsupportedSocketOperationError:
+ return QLocalSocket::UnsupportedSocketOperationError;
+ case QAbstractSocket::UnknownSocketError:
+ return QLocalSocket::UnknownSocketError;
+ default:
+#if defined QLOCALSOCKET_DEBUG
+ qWarning() << "QLocalSocket error not handled:" << d->unixSocket.error();
+#endif
+ break;
+ }
+ return UnknownSocketError;
+}
+
+bool QLocalSocket::isValid() const
+{
+ Q_D(const QLocalSocket);
+ return d->unixSocket.isValid();
+}
+
+qint64 QLocalSocket::readBufferSize() const
+{
+ Q_D(const QLocalSocket);
+ return d->unixSocket.readBufferSize();
+}
+
+void QLocalSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QLocalSocket);
+ d->unixSocket.setReadBufferSize(size);
+}
+
+bool QLocalSocket::waitForConnected(int msec)
+{
+ Q_D(QLocalSocket);
+ if (state() != ConnectingState)
+ return (state() == ConnectedState);
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(d->connectingSocket, &fds);
+
+ timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ // timeout can not be 0 or else select will return an error.
+ if (0 == msec)
+ timeout.tv_usec = 1000;
+
+ int result = -1;
+ // on Linux timeout will be updated by select, but _not_ on other systems.
+ QElapsedTimer timer;
+ timer.start();
+ while (state() == ConnectingState
+ && (-1 == msec || timer.elapsed() < msec)) {
+#ifdef Q_OS_SYMBIAN
+ // On Symbian, ready-to-write is signaled when non-blocking socket
+ // connect is finised. Is ready-to-read really used on other
+ // UNIX paltforms when using non-blocking AF_UNIX socket?
+ result = ::select(d->connectingSocket + 1, 0, &fds, 0, &timeout);
+#else
+ result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
+#endif
+ if (-1 == result && errno != EINTR) {
+ d->errorOccurred( QLocalSocket::UnknownSocketError,
+ QLatin1String("QLocalSocket::waitForConnected"));
+ break;
+ }
+ if (result > 0)
+ d->_q_connectToSocket();
+ }
+
+ return (state() == ConnectedState);
+}
+
+bool QLocalSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QLocalSocket);
+ if (state() == UnconnectedState) {
+ qWarning() << "QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState";
+ return false;
+ }
+ return (d->unixSocket.waitForDisconnected(msecs));
+}
+
+bool QLocalSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QLocalSocket);
+ if (state() == QLocalSocket::UnconnectedState)
+ return false;
+ return (d->unixSocket.waitForReadyRead(msecs));
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
new file mode 100644
index 0000000000..185f57481a
--- /dev/null
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -0,0 +1,633 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket_p.h"
+
+#include <private/qthread_p.h>
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void QLocalSocketPrivate::init()
+{
+ Q_Q(QLocalSocket);
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ dataReadNotifier = new QWinEventNotifier(overlapped.hEvent, q);
+ q->connect(dataReadNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_notified()));
+}
+
+void QLocalSocketPrivate::setErrorString(const QString &function)
+{
+ Q_Q(QLocalSocket);
+ BOOL windowsError = GetLastError();
+ QLocalSocket::LocalSocketState currentState = state;
+
+ // If the connectToServer fails due to WaitNamedPipe() time-out, assume ConnectionError
+ if (state == QLocalSocket::ConnectingState && windowsError == ERROR_SEM_TIMEOUT)
+ windowsError = ERROR_NO_DATA;
+
+ switch (windowsError) {
+ case ERROR_PIPE_NOT_CONNECTED:
+ case ERROR_BROKEN_PIPE:
+ case ERROR_NO_DATA:
+ error = QLocalSocket::ConnectionError;
+ errorString = QLocalSocket::tr("%1: Connection error").arg(function);
+ state = QLocalSocket::UnconnectedState;
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ error = QLocalSocket::ServerNotFoundError;
+ errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
+ state = QLocalSocket::UnconnectedState;
+ break;
+ case ERROR_ACCESS_DENIED:
+ error = QLocalSocket::SocketAccessError;
+ errorString = QLocalSocket::tr("%1: Access denied").arg(function);
+ state = QLocalSocket::UnconnectedState;
+ break;
+ default:
+ error = QLocalSocket::UnknownSocketError;
+ errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(windowsError);
+#if defined QLOCALSOCKET_DEBUG
+ qWarning() << "QLocalSocket error not handled:" << errorString;
+#endif
+ state = QLocalSocket::UnconnectedState;
+ }
+
+ if (currentState != state) {
+ q->emit stateChanged(state);
+ if (state == QLocalSocket::UnconnectedState)
+ q->emit disconnected();
+ }
+ emit q->error(error);
+}
+
+QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
+ handle(INVALID_HANDLE_VALUE),
+ pipeWriter(0),
+ readBufferMaxSize(0),
+ actualReadBufferSize(0),
+ error(QLocalSocket::UnknownSocketError),
+ readSequenceStarted(false),
+ pendingReadyRead(false),
+ pipeClosed(false),
+ state(QLocalSocket::UnconnectedState)
+{
+}
+
+QLocalSocketPrivate::~QLocalSocketPrivate()
+{
+ destroyPipeHandles();
+ CloseHandle(overlapped.hEvent);
+}
+
+void QLocalSocketPrivate::destroyPipeHandles()
+{
+ if (handle != INVALID_HANDLE_VALUE) {
+ DisconnectNamedPipe(handle);
+ CloseHandle(handle);
+ }
+}
+
+void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ if (state() == ConnectedState || state() == ConnectingState)
+ return;
+
+ d->error = QLocalSocket::UnknownSocketError;
+ d->errorString = QString();
+ d->state = ConnectingState;
+ emit stateChanged(d->state);
+ if (name.isEmpty()) {
+ d->error = QLocalSocket::ServerNotFoundError;
+ setErrorString(QLocalSocket::tr("%1: Invalid name").arg(QLatin1String("QLocalSocket::connectToServer")));
+ d->state = UnconnectedState;
+ emit error(d->error);
+ emit stateChanged(d->state);
+ return;
+ }
+
+ QString pipePath = QLatin1String("\\\\.\\pipe\\");
+ if (name.startsWith(pipePath))
+ d->fullServerName = name;
+ else
+ d->fullServerName = pipePath + name;
+ // Try to open a named pipe
+ HANDLE localSocket;
+ forever {
+ DWORD permissions = (openMode & QIODevice::ReadOnly) ? GENERIC_READ : 0;
+ permissions |= (openMode & QIODevice::WriteOnly) ? GENERIC_WRITE : 0;
+ localSocket = CreateFile((const wchar_t *)d->fullServerName.utf16(), // pipe name
+ permissions,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ FILE_FLAG_OVERLAPPED,
+ NULL); // no template file
+
+ if (localSocket != INVALID_HANDLE_VALUE)
+ break;
+ DWORD error = GetLastError();
+ // It is really an error only if it is not ERROR_PIPE_BUSY
+ if (ERROR_PIPE_BUSY != error) {
+ break;
+ }
+
+ // All pipe instances are busy, so wait until connected or up to 5 seconds.
+ if (!WaitNamedPipe((const wchar_t *)d->fullServerName.utf16(), 5000))
+ break;
+ }
+
+ if (localSocket == INVALID_HANDLE_VALUE) {
+ d->setErrorString(QLatin1String("QLocalSocket::connectToServer"));
+ d->fullServerName = QString();
+ return;
+ }
+
+ // we have a valid handle
+ d->serverName = name;
+ if (setSocketDescriptor((quintptr)localSocket, ConnectedState, openMode)) {
+ d->handle = localSocket;
+ emit connected();
+ }
+}
+
+// This is reading from the buffer
+qint64 QLocalSocket::readData(char *data, qint64 maxSize)
+{
+ Q_D(QLocalSocket);
+
+ if (d->pipeClosed && d->actualReadBufferSize == 0)
+ return -1; // signal EOF
+
+ qint64 readSoFar;
+ // If startAsyncRead() read data, copy it to its destination.
+ if (maxSize == 1 && d->actualReadBufferSize > 0) {
+ *data = d->readBuffer.getChar();
+ d->actualReadBufferSize--;
+ readSoFar = 1;
+ } else {
+ qint64 bytesToRead = qMin(qint64(d->actualReadBufferSize), maxSize);
+ readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = d->readBuffer.readPointer();
+ int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ qint64(d->readBuffer.nextDataBlockSize()));
+ memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ d->readBuffer.free(bytesToReadFromThisBlock);
+ d->actualReadBufferSize -= bytesToReadFromThisBlock;
+ }
+ }
+
+ if (d->pipeClosed) {
+ if (d->actualReadBufferSize == 0)
+ QTimer::singleShot(0, this, SLOT(_q_pipeClosed()));
+ } else {
+ if (!d->readSequenceStarted)
+ d->startAsyncRead();
+ d->checkReadyRead();
+ }
+
+ return readSoFar;
+}
+
+/*!
+ \internal
+ Schedules or cancels a readyRead() emission depending on actual data availability
+ */
+void QLocalSocketPrivate::checkReadyRead()
+{
+ if (actualReadBufferSize > 0) {
+ if (!pendingReadyRead) {
+ Q_Q(QLocalSocket);
+ QTimer::singleShot(0, q, SLOT(_q_emitReadyRead()));
+ pendingReadyRead = true;
+ }
+ } else {
+ pendingReadyRead = false;
+ }
+}
+
+/*!
+ \internal
+ Reads data from the socket into the readbuffer
+ */
+void QLocalSocketPrivate::startAsyncRead()
+{
+ do {
+ DWORD bytesToRead = checkPipeState();
+ if (pipeClosed)
+ return;
+
+ if (bytesToRead == 0) {
+ // There are no bytes in the pipe but we need to
+ // start the overlapped read with some buffer size.
+ bytesToRead = initialReadBufferSize;
+ }
+
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (bytesToRead == 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the pipe.
+ return;
+ }
+ }
+
+ char *ptr = readBuffer.reserve(bytesToRead);
+
+ readSequenceStarted = true;
+ if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) {
+ completeAsyncRead();
+ } else {
+ switch (GetLastError()) {
+ case ERROR_IO_PENDING:
+ // This is not an error. We're getting notified, when data arrives.
+ return;
+ case ERROR_MORE_DATA:
+ // This is not an error. The synchronous read succeeded.
+ // We're connected to a message mode pipe and the message
+ // didn't fit into the pipe's system buffer.
+ completeAsyncRead();
+ break;
+ case ERROR_PIPE_NOT_CONNECTED:
+ {
+ // It may happen, that the other side closes the connection directly
+ // after writing data. Then we must set the appropriate socket state.
+ pipeClosed = true;
+ Q_Q(QLocalSocket);
+ emit q->readChannelFinished();
+ return;
+ }
+ default:
+ setErrorString(QLatin1String("QLocalSocketPrivate::startAsyncRead"));
+ return;
+ }
+ }
+ } while (!readSequenceStarted);
+}
+
+/*!
+ \internal
+ Sets the correct size of the read buffer after a read operation.
+ Returns false, if an error occurred or the connection dropped.
+ */
+bool QLocalSocketPrivate::completeAsyncRead()
+{
+ ResetEvent(overlapped.hEvent);
+ readSequenceStarted = false;
+
+ DWORD bytesRead;
+ if (!GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE)) {
+ switch (GetLastError()) {
+ case ERROR_MORE_DATA:
+ // This is not an error. We're connected to a message mode
+ // pipe and the message didn't fit into the pipe's system
+ // buffer. We will read the remaining data in the next call.
+ break;
+ case ERROR_PIPE_NOT_CONNECTED:
+ return false;
+ default:
+ setErrorString(QLatin1String("QLocalSocketPrivate::completeAsyncRead"));
+ return false;
+ }
+ }
+
+ actualReadBufferSize += bytesRead;
+ readBuffer.truncate(actualReadBufferSize);
+ return true;
+}
+
+qint64 QLocalSocket::writeData(const char *data, qint64 maxSize)
+{
+ Q_D(QLocalSocket);
+ if (!d->pipeWriter) {
+ d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
+ connect(d->pipeWriter, SIGNAL(canWrite()), this, SLOT(_q_canWrite()));
+ connect(d->pipeWriter, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
+ d->pipeWriter->start();
+ }
+ return d->pipeWriter->write(data, maxSize);
+}
+
+void QLocalSocket::abort()
+{
+ Q_D(QLocalSocket);
+ if (d->pipeWriter) {
+ delete d->pipeWriter;
+ d->pipeWriter = 0;
+ }
+ close();
+}
+
+/*!
+ \internal
+ Returns the number of available bytes in the pipe.
+ Sets QLocalSocketPrivate::pipeClosed to true if the connection is broken.
+ */
+DWORD QLocalSocketPrivate::checkPipeState()
+{
+ Q_Q(QLocalSocket);
+ DWORD bytes;
+ if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) {
+ return bytes;
+ } else {
+ if (!pipeClosed) {
+ pipeClosed = true;
+ emit q->readChannelFinished();
+ if (actualReadBufferSize == 0)
+ QTimer::singleShot(0, q, SLOT(_q_pipeClosed()));
+ }
+ }
+ return 0;
+}
+
+void QLocalSocketPrivate::_q_pipeClosed()
+{
+ Q_Q(QLocalSocket);
+ q->close();
+}
+
+qint64 QLocalSocket::bytesAvailable() const
+{
+ Q_D(const QLocalSocket);
+ qint64 available = QIODevice::bytesAvailable();
+ available += (qint64) d->actualReadBufferSize;
+ return available;
+}
+
+qint64 QLocalSocket::bytesToWrite() const
+{
+ Q_D(const QLocalSocket);
+ return (d->pipeWriter) ? d->pipeWriter->bytesToWrite() : 0;
+}
+
+bool QLocalSocket::canReadLine() const
+{
+ Q_D(const QLocalSocket);
+ if (state() != ConnectedState)
+ return false;
+ return (QIODevice::canReadLine()
+ || d->readBuffer.indexOf('\n', d->actualReadBufferSize) != -1);
+}
+
+void QLocalSocket::close()
+{
+ Q_D(QLocalSocket);
+ if (state() == UnconnectedState)
+ return;
+
+ QIODevice::close();
+ d->state = ClosingState;
+ emit stateChanged(d->state);
+ if (!d->pipeClosed)
+ emit readChannelFinished();
+ d->serverName = QString();
+ d->fullServerName = QString();
+
+ if (state() != UnconnectedState && bytesToWrite() > 0) {
+ disconnectFromServer();
+ return;
+ }
+ d->readSequenceStarted = false;
+ d->pendingReadyRead = false;
+ d->pipeClosed = false;
+ d->destroyPipeHandles();
+ d->handle = INVALID_HANDLE_VALUE;
+ ResetEvent(d->overlapped.hEvent);
+ d->state = UnconnectedState;
+ emit stateChanged(d->state);
+ emit disconnected();
+ if (d->pipeWriter) {
+ delete d->pipeWriter;
+ d->pipeWriter = 0;
+ }
+}
+
+bool QLocalSocket::flush()
+{
+ Q_D(QLocalSocket);
+ if (d->pipeWriter)
+ return d->pipeWriter->waitForWrite(0);
+ return false;
+}
+
+void QLocalSocket::disconnectFromServer()
+{
+ Q_D(QLocalSocket);
+
+ // Are we still connected?
+ if (!isValid()) {
+ // If we have unwritten data, the pipeWriter is still present.
+ // It must be destroyed before close() to prevent an infinite loop.
+ delete d->pipeWriter;
+ d->pipeWriter = 0;
+ }
+
+ flush();
+ if (d->pipeWriter && d->pipeWriter->bytesToWrite() != 0) {
+ d->state = QLocalSocket::ClosingState;
+ emit stateChanged(d->state);
+ } else {
+ close();
+ }
+}
+
+QLocalSocket::LocalSocketError QLocalSocket::error() const
+{
+ Q_D(const QLocalSocket);
+ return d->error;
+}
+
+bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
+ LocalSocketState socketState, OpenMode openMode)
+{
+ Q_D(QLocalSocket);
+ d->readBuffer.clear();
+ d->actualReadBufferSize = 0;
+ QIODevice::open(openMode);
+ d->handle = (int*)socketDescriptor;
+ d->state = socketState;
+ emit stateChanged(d->state);
+ if (d->state == ConnectedState && openMode.testFlag(QIODevice::ReadOnly)) {
+ d->startAsyncRead();
+ d->checkReadyRead();
+ }
+ return true;
+}
+
+void QLocalSocketPrivate::_q_canWrite()
+{
+ Q_Q(QLocalSocket);
+ if (state == QLocalSocket::ClosingState)
+ q->close();
+}
+
+void QLocalSocketPrivate::_q_notified()
+{
+ Q_Q(QLocalSocket);
+ if (!completeAsyncRead()) {
+ pipeClosed = true;
+ emit q->readChannelFinished();
+ if (actualReadBufferSize == 0)
+ QTimer::singleShot(0, q, SLOT(_q_pipeClosed()));
+ return;
+ }
+ startAsyncRead();
+ pendingReadyRead = false;
+ emit q->readyRead();
+}
+
+void QLocalSocketPrivate::_q_emitReadyRead()
+{
+ if (pendingReadyRead) {
+ Q_Q(QLocalSocket);
+ pendingReadyRead = false;
+ emit q->readyRead();
+ }
+}
+
+quintptr QLocalSocket::socketDescriptor() const
+{
+ Q_D(const QLocalSocket);
+ return (quintptr)d->handle;
+}
+
+qint64 QLocalSocket::readBufferSize() const
+{
+ Q_D(const QLocalSocket);
+ return d->readBufferMaxSize;
+}
+
+void QLocalSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QLocalSocket);
+ d->readBufferMaxSize = size;
+}
+
+bool QLocalSocket::waitForConnected(int msecs)
+{
+ Q_UNUSED(msecs);
+ return (state() == ConnectedState);
+}
+
+bool QLocalSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QLocalSocket);
+ if (state() == UnconnectedState)
+ return false;
+ if (!openMode().testFlag(QIODevice::ReadOnly)) {
+ qWarning("QLocalSocket::waitForDisconnected isn't supported for write only pipes.");
+ return false;
+ }
+ QIncrementalSleepTimer timer(msecs);
+ forever {
+ d->checkPipeState();
+ if (d->pipeClosed)
+ close();
+ if (state() == UnconnectedState)
+ return true;
+ Sleep(timer.nextSleepTime());
+ if (timer.hasTimedOut())
+ break;
+ }
+
+ return false;
+}
+
+bool QLocalSocket::isValid() const
+{
+ Q_D(const QLocalSocket);
+ return d->handle != INVALID_HANDLE_VALUE;
+}
+
+bool QLocalSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QLocalSocket);
+
+ if (bytesAvailable() > 0)
+ return true;
+
+ if (d->state != QLocalSocket::ConnectedState)
+ return false;
+
+ // We already know that the pipe is gone, but did not enter the event loop yet.
+ if (d->pipeClosed) {
+ close();
+ return false;
+ }
+
+ Q_ASSERT(d->readSequenceStarted);
+ DWORD result = WaitForSingleObject(d->overlapped.hEvent, msecs == -1 ? INFINITE : msecs);
+ switch (result) {
+ case WAIT_OBJECT_0:
+ d->_q_notified();
+ // We just noticed that the pipe is gone.
+ if (d->pipeClosed) {
+ close();
+ return false;
+ }
+ return true;
+ case WAIT_TIMEOUT:
+ return false;
+ }
+
+ qWarning("QLocalSocket::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError()));
+ return false;
+}
+
+bool QLocalSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(const QLocalSocket);
+ if (!d->pipeWriter)
+ return false;
+
+ // Wait for the pipe writer to acknowledge that it has
+ // written. This will succeed if either the pipe writer has
+ // already written the data, or if it manages to write data
+ // within the given timeout.
+ return d->pipeWriter->waitForWrite(msecs);
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
new file mode 100644
index 0000000000..f5a88e2cc7
--- /dev/null
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -0,0 +1,1258 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+
+/*! \class QNativeSocketEngine
+ \internal
+
+ \brief The QNativeSocketEngine class provides low level access to a socket.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ QtSocketLayer provides basic socket functionality provided by the
+ operating system. It also keeps track of what state the socket is
+ in, and which errors that occur.
+
+ The classes QTcpSocket, QUdpSocket and QTcpServer provide a
+ higher level API, and are in general more useful for the common
+ application.
+
+ There are two main ways of initializing the a QNativeSocketEngine; either
+ create a new socket by passing the socket type (TcpSocket or
+ UdpSocket) and network layer protocol (IPv4Protocol or
+ IPv6Protocol) to initialize(), or pass an existing socket
+ descriptor and have QNativeSocketEngine determine the type and protocol
+ itself. The native socket descriptor can later be fetched by
+ calling socketDescriptor(). The socket is made non-blocking, but
+ blocking behavior can still be achieved by calling waitForRead()
+ and waitForWrite(). isValid() can be called to check if the socket
+ has been successfully initialized and is ready to use.
+
+ To connect to a host, determine its address and pass this and the
+ port number to connectToHost(). The socket can then be used as a
+ TCP or UDP client. Otherwise; bind(), listen() and accept() are
+ used to have the socket function as a TCP or UDP server. Call
+ close() to close the socket.
+
+ bytesAvailable() is called to determine how much data is available
+ for reading. read() and write() are used by both TCP and UDP
+ clients to exchange data with the connected peer. UDP clients can
+ also call hasMoreDatagrams(), nextDatagramSize(),
+ readDatagram(), and writeDatagram().
+
+ Call state() to determine the state of the socket, for
+ example, ListeningState or ConnectedState. socketType() tells
+ whether the socket is a TCP socket or a UDP socket, or if the
+ socket type is unknown. protocol() is used to determine the
+ socket's network layer protocol.
+
+ localAddress(), localPort() are called to find the address and
+ port that are currently bound to the socket. If the socket is
+ connected, peerAddress() and peerPort() determine the address and
+ port of the connected peer.
+
+ Finally, if any function should fail, error() and
+ errorString() can be called to determine the cause of the error.
+*/
+
+#include <qabstracteventdispatcher.h>
+#include <qsocketnotifier.h>
+#include <qnetworkinterface.h>
+
+#include "qnativesocketengine_p.h"
+#include <private/qthread_p.h>
+#include <private/qobject_p.h>
+
+#if !defined(QT_NO_NETWORKPROXY)
+# include "qnetworkproxy.h"
+# include "qabstractsocket.h"
+# include "qtcpserver.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define QNATIVESOCKETENGINE_DEBUG
+
+#define Q_VOID
+
+// Common constructs
+#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
+ if (!isValid()) { \
+ qWarning(""#function" was called on an uninitialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
+ if (isValid()) { \
+ qWarning(""#function" was called on an already initialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_STATE(function, checkState, returnValue) do { \
+ if (d->socketState != (checkState)) { \
+ qWarning(""#function" was not called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
+ if (d->socketState == (checkState)) { \
+ qWarning(""#function" was called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
+ if (d->socketState != (state1) && d->socketState != (state2)) { \
+ qWarning(""#function" was called" \
+ " not in "#state1" or "#state2); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_TYPE(function, type, returnValue) do { \
+ if (d->socketType != (type)) { \
+ qWarning(#function" was called by a" \
+ " socket other than "#type""); \
+ return (returnValue); \
+ } } while (0)
+#define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
+
+/*! \internal
+ Constructs the private class and initializes all data members.
+
+ On Windows, WSAStartup is called "recursively" for every
+ concurrent QNativeSocketEngine. This is safe, because WSAStartup and
+ WSACleanup are reference counted.
+*/
+QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
+ socketDescriptor(-1),
+ readNotifier(0),
+ writeNotifier(0),
+ exceptNotifier(0)
+{
+}
+
+/*! \internal
+ Destructs the private class.
+*/
+QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
+{
+}
+
+/*! \internal
+
+ Sets the error and error string if not set already. The only
+ interesting error is the first one that occurred, and not the last
+ one.
+*/
+void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
+{
+ if (hasSetSocketError) {
+ // Only set socket errors once for one engine; expect the
+ // socket to recreate its engine after an error. Note: There's
+ // one exception: SocketError(11) bypasses this as it's purely
+ // a temporary internal error condition.
+ // Another exception is the way the waitFor*() functions set
+ // an error when a timeout occurs. After the call to setError()
+ // they reset the hasSetSocketError to false
+ return;
+ }
+ if (error != QAbstractSocket::SocketError(11))
+ hasSetSocketError = true;
+
+ socketError = error;
+
+ switch (errorString) {
+ case NonBlockingInitFailedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to initialize non-blocking socket");
+ break;
+ case BroadcastingInitFailedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to initialize broadcast socket");
+ break;
+ case NoIpV6ErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support");
+ break;
+ case RemoteHostClosedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The remote host closed the connection");
+ break;
+ case TimeOutErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network operation timed out");
+ break;
+ case ResourceErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Out of resources");
+ break;
+ case OperationUnsupportedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unsupported socket operation");
+ break;
+ case ProtocolUnsupportedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Protocol type not supported");
+ break;
+ case InvalidSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Invalid socket descriptor");
+ break;
+ case HostUnreachableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Host unreachable");
+ break;
+ case NetworkUnreachableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network unreachable");
+ break;
+ case AccessErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Permission denied");
+ break;
+ case ConnectionTimeOutErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Connection timed out");
+ break;
+ case ConnectionRefusedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Connection refused");
+ break;
+ case AddressInuseErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The bound address is already in use");
+ break;
+ case AddressNotAvailableErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The address is not available");
+ break;
+ case AddressProtectedErrorString:
+ socketErrorString = QNativeSocketEngine::tr("The address is protected");
+ break;
+ case DatagramTooLargeErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Datagram was too large to send");
+ break;
+ case SendDatagramErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to send a message");
+ break;
+ case ReceiveDatagramErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to receive a message");
+ break;
+ case WriteErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unable to write");
+ break;
+ case ReadErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Network error");
+ break;
+ case PortInuseErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Another socket is already listening on the same port");
+ break;
+ case NotSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Operation on non-socket");
+ break;
+ case InvalidProxyTypeString:
+ socketErrorString = QNativeSocketEngine::tr("The proxy type is invalid for this operation");
+ break;
+ case UnknownSocketErrorString:
+ socketErrorString = QNativeSocketEngine::tr("Unknown error");
+ break;
+ }
+}
+
+bool QNativeSocketEnginePrivate::checkProxy(const QHostAddress &address)
+{
+ if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6)
+ return true;
+
+#if !defined(QT_NO_NETWORKPROXY)
+ QObject *parent = q_func()->parent();
+ QNetworkProxy proxy;
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) {
+ proxy = socket->proxy();
+ } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) {
+ proxy = server->proxy();
+ } else {
+ // no parent -> no proxy
+ return true;
+ }
+
+ if (proxy.type() == QNetworkProxy::DefaultProxy)
+ proxy = QNetworkProxy::applicationProxy();
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy &&
+ proxy.type() != QNetworkProxy::NoProxy) {
+ // QNativeSocketEngine doesn't do proxies
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::InvalidProxyTypeString);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+/*!
+ Constructs a QNativeSocketEngine.
+
+ \sa initialize()
+*/
+QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
+ : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
+{
+}
+
+/*!
+ Destructs a QNativeSocketEngine.
+*/
+QNativeSocketEngine::~QNativeSocketEngine()
+{
+ close();
+}
+
+/*!
+ Initializes a QNativeSocketEngine by creating a new socket of type \a
+ socketType and network layer protocol \a protocol. Returns true on
+ success; otherwise returns false.
+
+ If the socket was already initialized, this function closes the
+ socket before reeinitializing it.
+
+ The new socket is non-blocking, and for UDP sockets it's also
+ broadcast enabled.
+*/
+bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QNativeSocketEngine);
+ if (isValid())
+ close();
+
+#if defined(QT_NO_IPV6)
+ if (protocol == QAbstractSocket::IPv6Protocol) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::NoIpV6ErrorString);
+ return false;
+ }
+#endif
+
+ // Create the socket
+ if (!d->createNewSocket(socketType, protocol)) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString typeStr = QLatin1String("UnknownSocketType");
+ if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
+ else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
+ QString protocolStr = QLatin1String("UnknownProtocol");
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
+ qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s",
+ typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+
+ // Make sure we receive out-of-band data
+ if (socketType == QAbstractSocket::TcpSocket
+ && !setOption(ReceiveOutOfBandData, 1)) {
+ qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data");
+ }
+
+ // Before Qt 4.6, we always set the send and receive buffer size to 49152 as
+ // this was found to be an optimal value. However, modern OS
+ // all have some kind of auto tuning for this and we therefore don't set
+ // this explictly anymore.
+ // If it introduces any performance regressions for Qt 4.6.x (x > 0) then
+ // it will be put back in.
+ //
+ // You can use tests/manual/qhttpnetworkconnection to test HTTP download speed
+ // with this.
+ //
+ // pre-4.6:
+ // setReceiveBufferSize(49152);
+ // setSendBufferSize(49152);
+
+ d->socketType = socketType;
+ d->socketProtocol = protocol;
+ return true;
+}
+
+/*! \overload
+
+ Initializes the socket using \a socketDescriptor instead of
+ creating a new one. The socket type and network layer protocol are
+ determined automatically. The socket's state is set to \a
+ socketState.
+
+ If the socket type is either TCP or UDP, it is made non-blocking.
+ UDP sockets are also broadcast enabled.
+ */
+bool QNativeSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState)
+{
+ Q_D(QNativeSocketEngine);
+
+ if (isValid())
+ close();
+
+ d->socketDescriptor = socketDescriptor;
+
+ // determine socket type and protocol
+ if (!d->fetchConnectionParameters()) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEngine::initialize(socketDescriptor == %i) failed: %s",
+ socketDescriptor, d->socketErrorString.toLatin1().constData());
+#endif
+ d->socketDescriptor = -1;
+ return false;
+ }
+
+ if (d->socketType != QAbstractSocket::UnknownSocketType) {
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (d->socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+ }
+
+ d->socketState = socketState;
+ return true;
+}
+
+/*!
+ Returns true if the socket is valid; otherwise returns false. A
+ socket is valid if it has not been successfully initialized, or if
+ it has been closed.
+*/
+bool QNativeSocketEngine::isValid() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->socketDescriptor != -1;
+}
+
+/*!
+ Returns the native socket descriptor. Any use of this descriptor
+ stands the risk of being non-portable.
+*/
+int QNativeSocketEngine::socketDescriptor() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->socketDescriptor;
+}
+
+/*!
+ Connects to the IP address and port specified by \a address and \a
+ port. If the connection is established, this function returns true
+ and the socket enters ConnectedState. Otherwise, false is
+ returned.
+
+ If false is returned, state() should be called to see if the
+ socket is in ConnectingState. If so, a delayed TCP connection is
+ taking place, and connectToHost() must be called again later to
+ determine if the connection was established successfully or
+ not. The second connection attempt must be made when the socket is
+ ready for writing. This state can be determined either by
+ connecting a QSocketNotifier to the socket descriptor returned by
+ socketDescriptor(), or by calling the blocking function
+ waitForWrite().
+
+ Example:
+ \snippet doc/src/snippets/code/src_network_socket_qnativesocketengine.cpp 0
+
+ Otherwise, error() should be called to determine the cause of the
+ error.
+*/
+bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::connectToHost(), false);
+
+#if defined (QT_NO_IPV6)
+ if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::NoIpV6ErrorString);
+ return false;
+ }
+#endif
+ if (!d->checkProxy(address))
+ return false;
+
+ Q_CHECK_STATES(QNativeSocketEngine::connectToHost(),
+ QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false);
+
+ d->peerAddress = address;
+ d->peerPort = port;
+ bool connected = d->nativeConnect(address, port);
+ if (connected)
+ d->fetchConnectionParameters();
+
+ return connected;
+}
+
+/*!
+ If there's a connection activity on the socket, process it. Then
+ notify our parent if there really was activity.
+*/
+void QNativeSocketEngine::connectionNotification()
+{
+ Q_D(QNativeSocketEngine);
+ Q_ASSERT(state() == QAbstractSocket::ConnectingState);
+
+ connectToHost(d->peerAddress, d->peerPort);
+ if (state() != QAbstractSocket::ConnectingState) {
+ // we changed states
+ QAbstractSocketEngine::connectionNotification();
+ }
+}
+
+/*!
+ Connects to the remote host name given by \a name on port \a
+ port. When this function is called, the upper-level will not
+ perform a hostname lookup.
+
+ The native socket engine does not support this operation,
+ but some other socket engines (notably proxy-based ones) do.
+*/
+bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
+{
+ Q_UNUSED(name);
+ Q_UNUSED(port);
+ Q_D(QNativeSocketEngine);
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
+ return false;
+}
+
+/*!
+ Binds the socket to the address \a address and port \a
+ port. Returns true on success; otherwise false is returned. The
+ port may be 0, in which case an arbitrary unused port is assigned
+ automatically by the operating system.
+
+ Servers call this function to set up the server's address and
+ port. TCP servers must in addition call listen() after bind().
+*/
+bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false);
+
+#if defined (QT_NO_IPV6)
+ if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::NoIpV6ErrorString);
+ return false;
+ }
+#endif
+ if (!d->checkProxy(address))
+ return false;
+
+ Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false);
+
+ if (!d->nativeBind(address, port))
+ return false;
+
+ d->fetchConnectionParameters();
+ return true;
+}
+
+/*!
+ Prepares a TCP server for accepting incoming connections. This
+ function must be called after bind(), and only by TCP sockets.
+
+ After this function has been called, pending client connections
+ are detected by checking if the socket is ready for reading. This
+ can be done by either creating a QSocketNotifier, passing the
+ socket descriptor returned by socketDescriptor(), or by calling
+ the blocking function waitForRead().
+
+ Example:
+ \snippet doc/src/snippets/code/src_network_socket_qnativesocketengine.cpp 1
+
+ \sa bind(), accept()
+*/
+bool QNativeSocketEngine::listen()
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
+ Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
+
+ // We're using a backlog of 50. Most modern kernels support TCP
+ // syncookies by default, and if they do, the backlog is ignored.
+ // When there is no support for TCP syncookies, this value is
+ // fine.
+ return d->nativeListen(50);
+}
+
+/*!
+ Accepts a pending connection from the socket, which must be in
+ ListeningState, and returns its socket descriptor. If no pending
+ connections are available, -1 is returned.
+
+ \sa bind(), listen()
+*/
+int QNativeSocketEngine::accept()
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
+ Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, false);
+
+ return d->nativeAccept();
+}
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+/*!
+ \since 4.8
+*/
+bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false);
+ Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->nativeJoinMulticastGroup(groupAddress, iface);
+}
+
+/*!
+ \since 4.8
+*/
+bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::leaveMulticastGroup(), false);
+ Q_CHECK_STATE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->nativeLeaveMulticastGroup(groupAddress, iface);
+}
+
+/*! \since 4.8 */
+QNetworkInterface QNativeSocketEngine::multicastInterface() const
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::multicastInterface(), QNetworkInterface());
+ Q_CHECK_TYPE(QNativeSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
+ return d->nativeMulticastInterface();
+}
+
+/*! \since 4.8 */
+bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setMulticastInterface(), false);
+ Q_CHECK_TYPE(QNativeSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
+ return d->nativeSetMulticastInterface(iface);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
+/*!
+ Returns the number of bytes that are currently available for
+ reading. On error, -1 is returned.
+
+ For UDP sockets, this function returns the accumulated size of all
+ pending datagrams, and it is therefore more useful for UDP sockets
+ to call hasPendingDatagrams() and pendingDatagramSize().
+*/
+qint64 QNativeSocketEngine::bytesAvailable() const
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false);
+
+ return d->nativeBytesAvailable();
+}
+
+/*!
+ Returns true if there is at least one datagram pending. This
+ function is only called by UDP sockets, where a datagram can have
+ a size of 0. TCP sockets call bytesAvailable().
+*/
+bool QNativeSocketEngine::hasPendingDatagrams() const
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false);
+ Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
+
+ return d->nativeHasPendingDatagrams();
+}
+
+/*!
+ Returns the size of the pending datagram, or -1 if no datagram is
+ pending. A datagram size of 0 is perfectly valid. This function is
+ called by UDP sockets before receiveMessage(). For TCP sockets,
+ call bytesAvailable().
+*/
+qint64 QNativeSocketEngine::pendingDatagramSize() const
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::pendingDatagramSize(), -1);
+ Q_CHECK_TYPE(QNativeSocketEngine::pendingDatagramSize(), QAbstractSocket::UdpSocket, false);
+
+ return d->nativePendingDatagramSize();
+}
+
+/*!
+ Reads up to \a maxSize bytes of a datagram from the socket,
+ stores it in \a data and returns the number of bytes read. The
+ address and port of the sender are stored in \a address and \a
+ port. If either of these pointers is 0, the corresponding value is
+ discarded.
+
+ To avoid unnecessarily loss of data, call pendingDatagramSize() to
+ determine the size of the pending message before reading it. If \a
+ maxSize is too small, the rest of the datagram will be lost.
+
+ Returns -1 if an error occurred.
+
+ \sa hasPendingDatagrams()
+*/
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
+ quint16 *port)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
+ Q_CHECK_TYPE(QNativeSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false);
+
+ return d->nativeReceiveDatagram(data, maxSize, address, port);
+}
+
+/*!
+ Writes a UDP datagram of size \a size bytes to the socket from
+ \a data to the address \a host on port \a port, and returns the
+ number of bytes written, or -1 if an error occurred.
+
+ Only one datagram is sent, and if there is too much data to fit
+ into a single datagram, the operation will fail and error()
+ will return QAbstractSocket::DatagramTooLargeError. Operating systems impose an
+ upper limit to the size of a datagram, but this size is different
+ on almost all platforms. Sending large datagrams is in general
+ disadvised, as even if they are sent successfully, they are likely
+ to be fragmented before arriving at their destination.
+
+ Experience has shown that it is in general safe to send datagrams
+ no larger than 512 bytes.
+
+ \sa readDatagram()
+*/
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size,
+ const QHostAddress &host, quint16 port)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
+ Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
+ return d->nativeSendDatagram(data, size, host, port);
+}
+
+/*!
+ Writes a block of \a size bytes from \a data to the socket.
+ Returns the number of bytes written, or -1 if an error occurred.
+*/
+qint64 QNativeSocketEngine::write(const char *data, qint64 size)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::write(), -1);
+ Q_CHECK_STATE(QNativeSocketEngine::write(), QAbstractSocket::ConnectedState, -1);
+ return d->nativeWrite(data, size);
+}
+
+
+qint64 QNativeSocketEngine::bytesToWrite() const
+{
+ return 0;
+}
+
+/*!
+ Reads up to \a maxSize bytes into \a data from the socket.
+ Returns the number of bytes read, or -1 if an error occurred.
+*/
+qint64 QNativeSocketEngine::read(char *data, qint64 maxSize)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::read(), -1);
+ Q_CHECK_STATES(QNativeSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);
+
+ qint64 readBytes = d->nativeRead(data, maxSize);
+
+ // Handle remote close
+ if (readBytes == 0 && d->socketType == QAbstractSocket::TcpSocket) {
+ d->setError(QAbstractSocket::RemoteHostClosedError,
+ QNativeSocketEnginePrivate::RemoteHostClosedErrorString);
+ close();
+ return -1;
+ } else if (readBytes == -1) {
+ if (!d->hasSetSocketError) {
+ d->hasSetSocketError = true;
+ d->socketError = QAbstractSocket::NetworkError;
+ d->socketErrorString = qt_error_string();
+ }
+ close();
+ return -1;
+ }
+ return readBytes;
+}
+
+/*!
+ Closes the socket. In order to use the socket again, initialize()
+ must be called.
+*/
+void QNativeSocketEngine::close()
+{
+ Q_D(QNativeSocketEngine);
+ if (d->readNotifier)
+ d->readNotifier->setEnabled(false);
+ if (d->writeNotifier)
+ d->writeNotifier->setEnabled(false);
+ if (d->exceptNotifier)
+ d->exceptNotifier->setEnabled(false);
+
+ if(d->socketDescriptor != -1) {
+ d->nativeClose();
+ d->socketDescriptor = -1;
+ }
+ d->socketState = QAbstractSocket::UnconnectedState;
+ d->hasSetSocketError = false;
+ d->localPort = 0;
+ d->localAddress.clear();
+ d->peerPort = 0;
+ d->peerAddress.clear();
+ if (d->readNotifier) {
+ qDeleteInEventHandler(d->readNotifier);
+ d->readNotifier = 0;
+ }
+ if (d->writeNotifier) {
+ qDeleteInEventHandler(d->writeNotifier);
+ d->writeNotifier = 0;
+ }
+ if (d->exceptNotifier) {
+ qDeleteInEventHandler(d->exceptNotifier);
+ d->exceptNotifier = 0;
+ }
+}
+
+/*!
+ Waits for \a msecs milliseconds or until the socket is ready for
+ reading. If \a timedOut is not 0 and \a msecs milliseconds have
+ passed, the value of \a timedOut is set to true.
+
+ Returns true if data is available for reading; otherwise returns
+ false.
+
+ This is a blocking function call; its use is disadvised in a
+ single threaded application, as the whole thread will stop
+ responding until the function returns. waitForRead() is most
+ useful when there is no event loop available. The general approach
+ is to create a QSocketNotifier, passing the socket descriptor
+ returned by socketDescriptor() to its constructor.
+*/
+bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, true);
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+/*!
+ Waits for \a msecs milliseconds or until the socket is ready for
+ writing. If \a timedOut is not 0 and \a msecs milliseconds have
+ passed, the value of \a timedOut is set to true.
+
+ Returns true if data is available for writing; otherwise returns
+ false.
+
+ This is a blocking function call; its use is disadvised in a
+ single threaded application, as the whole thread will stop
+ responding until the function returns. waitForWrite() is most
+ useful when there is no event loop available. The general approach
+ is to create a QSocketNotifier, passing the socket descriptor
+ returned by socketDescriptor() to its constructor.
+*/
+bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, false);
+ // On Windows, the socket is in connected state if a call to
+ // select(writable) is successful. In this case we should not
+ // issue a second call to WSAConnect()
+#if defined (Q_WS_WIN)
+ if (ret > 0) {
+ setState(QAbstractSocket::ConnectedState);
+ d_func()->fetchConnectionParameters();
+ return true;
+ } else {
+ int value = 0;
+ int valueSize = sizeof(value);
+ if (::getsockopt(d->socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
+ if (value == WSAECONNREFUSED) {
+ d->setError(QAbstractSocket::ConnectionRefusedError, QNativeSocketEnginePrivate::ConnectionRefusedErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ } else if (value == WSAETIMEDOUT) {
+ d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::ConnectionTimeOutErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ } else if (value == WSAEHOSTUNREACH) {
+ d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::HostUnreachableErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ }
+ }
+ }
+#endif
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite);
+ // On Windows, the socket is in connected state if a call to
+ // select(writable) is successful. In this case we should not
+ // issue a second call to WSAConnect()
+#if defined (Q_WS_WIN)
+ if (checkWrite && ((readyToWrite && *readyToWrite) || !readyToWrite) && ret > 0) {
+ setState(QAbstractSocket::ConnectedState);
+ d_func()->fetchConnectionParameters();
+ return true;
+ } else {
+ int value = 0;
+ int valueSize = sizeof(value);
+ if (::getsockopt(d->socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
+ if (value == WSAECONNREFUSED) {
+ d->setError(QAbstractSocket::ConnectionRefusedError, QNativeSocketEnginePrivate::ConnectionRefusedErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ } else if (value == WSAETIMEDOUT) {
+ d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::ConnectionTimeOutErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ } else if (value == WSAEHOSTUNREACH) {
+ d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::HostUnreachableErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return false;
+ }
+ }
+ }
+#endif
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+/*!
+ Returns the size of the operating system's socket receive
+ buffer. Depending on the operating system, this size may be
+ different from what has been set earlier with
+ setReceiveBufferSize().
+*/
+qint64 QNativeSocketEngine::receiveBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::receiveBufferSize(), -1);
+ return option(ReceiveBufferSocketOption);
+}
+
+/*!
+ Sets the size of the operating system receive buffer to \a size.
+
+ For clients, this should be set before connectToHost() is called;
+ otherwise it will have no effect. For servers, it should be called
+ before listen().
+
+ The operating system receive buffer size effectively limits two
+ things: how much data can be in transit at any one moment, and how
+ much data can be received in one iteration of the main event loop.
+ Setting the size of the receive buffer may have an impact on the
+ socket's performance.
+
+ The default value is operating system-dependent.
+*/
+void QNativeSocketEngine::setReceiveBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setReceiveBufferSize(), Q_VOID);
+ setOption(ReceiveBufferSocketOption, size);
+}
+
+/*!
+ Returns the size of the operating system send buffer. Depending on
+ the operating system, this size may be different from what has
+ been set earlier with setSendBufferSize().
+*/
+qint64 QNativeSocketEngine::sendBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), -1);
+ return option(SendBufferSocketOption);
+}
+
+/*!
+ Sets the size of the operating system send buffer to \a size.
+
+ The operating system send buffer size effectively limits how much
+ data can be in transit at any one moment. Setting the size of the
+ send buffer may have an impact on the socket's performance.
+
+ The default value is operating system-dependent.
+*/
+void QNativeSocketEngine::setSendBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), Q_VOID);
+ setOption(SendBufferSocketOption, size);
+}
+
+
+/*!
+ Sets the option \a option to the value \a value.
+*/
+bool QNativeSocketEngine::setOption(SocketOption option, int value)
+{
+ Q_D(QNativeSocketEngine);
+ return d->setOption(option, value);
+}
+
+/*!
+ Returns the value of the option \a socketOption.
+*/
+int QNativeSocketEngine::option(SocketOption socketOption) const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->option(socketOption);
+}
+
+bool QNativeSocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->readNotifier && d->readNotifier->isEnabled();
+}
+
+/*
+ \internal
+ \class QReadNotifier
+ \brief The QReadNotifer class is used to improve performance.
+
+ QReadNotifier is a private class used for performance reasons vs
+ connecting to the QSocketNotifier activated() signal.
+ */
+class QReadNotifier : public QSocketNotifier
+{
+public:
+ QReadNotifier(int fd, QNativeSocketEngine *parent)
+ : QSocketNotifier(fd, QSocketNotifier::Read, parent)
+ { engine = parent; }
+
+protected:
+ bool event(QEvent *);
+
+ QNativeSocketEngine *engine;
+};
+
+bool QReadNotifier::event(QEvent *e)
+{
+ if (e->type() == QEvent::SockAct) {
+ engine->readNotification();
+ return true;
+ }
+ return QSocketNotifier::event(e);
+}
+
+/*
+ \internal
+ \class QWriteNotifier
+ \brief The QWriteNotifer class is used to improve performance.
+
+ QWriteNotifier is a private class used for performance reasons vs
+ connecting to the QSocketNotifier activated() signal.
+ */
+class QWriteNotifier : public QSocketNotifier
+{
+public:
+ QWriteNotifier(int fd, QNativeSocketEngine *parent)
+ : QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; }
+
+protected:
+ bool event(QEvent *);
+
+ QNativeSocketEngine *engine;
+};
+
+bool QWriteNotifier::event(QEvent *e)
+{
+ if (e->type() == QEvent::SockAct) {
+ if (engine->state() == QAbstractSocket::ConnectingState)
+ engine->connectionNotification();
+ else
+ engine->writeNotification();
+ return true;
+ }
+ return QSocketNotifier::event(e);
+}
+
+class QExceptionNotifier : public QSocketNotifier
+{
+public:
+ QExceptionNotifier(int fd, QNativeSocketEngine *parent)
+ : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; }
+
+protected:
+ bool event(QEvent *);
+
+ QNativeSocketEngine *engine;
+};
+
+bool QExceptionNotifier::event(QEvent *e)
+{
+ if (e->type() == QEvent::SockAct) {
+ if (engine->state() == QAbstractSocket::ConnectingState)
+ engine->connectionNotification();
+ else
+ engine->exceptionNotification();
+ return true;
+ }
+ return QSocketNotifier::event(e);
+}
+
+void QNativeSocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->readNotifier) {
+ d->readNotifier->setEnabled(enable);
+ } else if (enable && d->threadData->eventDispatcher) {
+ d->readNotifier = new QReadNotifier(d->socketDescriptor, this);
+ d->readNotifier->setEnabled(true);
+ }
+}
+
+bool QNativeSocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->writeNotifier && d->writeNotifier->isEnabled();
+}
+
+void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->writeNotifier) {
+ d->writeNotifier->setEnabled(enable);
+ } else if (enable && d->threadData->eventDispatcher) {
+ d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this);
+ d->writeNotifier->setEnabled(true);
+ }
+}
+
+bool QNativeSocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QNativeSocketEngine);
+ return d->exceptNotifier && d->exceptNotifier->isEnabled();
+}
+
+void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QNativeSocketEngine);
+ if (d->exceptNotifier) {
+ d->exceptNotifier->setEnabled(enable);
+ } else if (enable && d->threadData->eventDispatcher) {
+ d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this);
+ d->exceptNotifier->setEnabled(true);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
new file mode 100644
index 0000000000..35054fb414
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNATIVESOCKETENGINE_P_H
+#define QNATIVESOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+#include "QtNetwork/qhostaddress.h"
+#include "private/qabstractsocketengine_p.h"
+#ifndef Q_OS_WIN
+# include "qplatformdefs.h"
+#else
+# include <winsock2.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// Use our own defines and structs which we know are correct
+# define QT_SS_MAXSIZE 128
+# define QT_SS_ALIGNSIZE (sizeof(qint64))
+# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short))
+# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE))
+struct qt_sockaddr_storage {
+ short ss_family;
+ char __ss_pad1[QT_SS_PAD1SIZE];
+ qint64 __ss_align;
+ char __ss_pad2[QT_SS_PAD2SIZE];
+};
+
+// sockaddr_in6 size changed between old and new SDK
+// Only the new version is the correct one, so always
+// use this structure.
+struct qt_in6_addr {
+ quint8 qt_s6_addr[16];
+};
+struct qt_sockaddr_in6 {
+ short sin6_family; /* AF_INET6 */
+ quint16 sin6_port; /* Transport level port number */
+ quint32 sin6_flowinfo; /* IPv6 flow information */
+ struct qt_in6_addr sin6_addr; /* IPv6 address */
+ quint32 sin6_scope_id; /* set of interfaces for a scope */
+};
+
+union qt_sockaddr {
+ sockaddr a;
+ sockaddr_in a4;
+ qt_sockaddr_in6 a6;
+ qt_sockaddr_storage storage;
+};
+
+class QNativeSocketEnginePrivate;
+#ifndef QT_NO_NETWORKINTERFACE
+class QNetworkInterface;
+#endif
+
+class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+public:
+ QNativeSocketEngine(QObject *parent = 0);
+ ~QNativeSocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ int socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif
+
+ qint64 bytesAvailable() const;
+
+ qint64 read(char *data, qint64 maxlen);
+ qint64 write(const char *data, qint64 len);
+
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+
+ qint64 bytesToWrite() const;
+
+ qint64 receiveBufferSize() const;
+ void setReceiveBufferSize(qint64 bufferSize);
+
+ qint64 sendBufferSize() const;
+ void setSendBufferSize(qint64 bufferSize);
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+public Q_SLOTS:
+ // non-virtual override;
+ void connectionNotification();
+
+private:
+ Q_DECLARE_PRIVATE(QNativeSocketEngine)
+ Q_DISABLE_COPY(QNativeSocketEngine)
+};
+
+#ifdef Q_OS_WIN
+class QWindowsSockInit
+{
+public:
+ QWindowsSockInit();
+ ~QWindowsSockInit();
+ int version;
+};
+#endif
+
+class QSocketNotifier;
+
+class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QNativeSocketEngine)
+public:
+ QNativeSocketEnginePrivate();
+ ~QNativeSocketEnginePrivate();
+
+ int socketDescriptor;
+
+ QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier;
+
+#ifdef Q_OS_WIN
+ QWindowsSockInit winSock;
+#endif
+
+ enum ErrorString {
+ NonBlockingInitFailedErrorString,
+ BroadcastingInitFailedErrorString,
+ NoIpV6ErrorString,
+ RemoteHostClosedErrorString,
+ TimeOutErrorString,
+ ResourceErrorString,
+ OperationUnsupportedErrorString,
+ ProtocolUnsupportedErrorString,
+ InvalidSocketErrorString,
+ HostUnreachableErrorString,
+ NetworkUnreachableErrorString,
+ AccessErrorString,
+ ConnectionTimeOutErrorString,
+ ConnectionRefusedErrorString,
+ AddressInuseErrorString,
+ AddressNotAvailableErrorString,
+ AddressProtectedErrorString,
+ DatagramTooLargeErrorString,
+ SendDatagramErrorString,
+ ReceiveDatagramErrorString,
+ WriteErrorString,
+ ReadErrorString,
+ PortInuseErrorString,
+ NotSocketErrorString,
+ InvalidProxyTypeString,
+
+ UnknownSocketErrorString = -1
+ };
+
+ void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
+
+ // native functions
+ int option(QNativeSocketEngine::SocketOption option) const;
+ bool setOption(QNativeSocketEngine::SocketOption option, int value);
+
+ bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol);
+
+ bool nativeConnect(const QHostAddress &address, quint16 port);
+ bool nativeBind(const QHostAddress &address, quint16 port);
+ bool nativeListen(int backlog);
+ int nativeAccept();
+#ifndef QT_NO_NETWORKINTERFACE
+ bool nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface nativeMulticastInterface() const;
+ bool nativeSetMulticastInterface(const QNetworkInterface &iface);
+#endif
+ qint64 nativeBytesAvailable() const;
+
+ bool nativeHasPendingDatagrams() const;
+ qint64 nativePendingDatagramSize() const;
+ qint64 nativeReceiveDatagram(char *data, qint64 maxLength,
+ QHostAddress *address, quint16 *port);
+ qint64 nativeSendDatagram(const char *data, qint64 length,
+ const QHostAddress &host, quint16 port);
+ qint64 nativeRead(char *data, qint64 maxLength);
+ qint64 nativeWrite(const char *data, qint64 length);
+ int nativeSelect(int timeout, bool selectForRead) const;
+ int nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const;
+
+ void nativeClose();
+
+ bool checkProxy(const QHostAddress &address);
+ bool fetchConnectionParameters();
+};
+
+QT_END_NAMESPACE
+
+#endif // QNATIVESOCKETENGINE_P_H
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
new file mode 100644
index 0000000000..43184271e5
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -0,0 +1,1125 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+#include "qnativesocketengine_p.h"
+#include "private/qnet_unix_p.h"
+#include "qiodevice.h"
+#include "qhostaddress.h"
+#include "qelapsedtimer.h"
+#include "qvarlengtharray.h"
+#include "qnetworkinterface.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifndef QT_NO_IPV6IFNAME
+#include <net/if.h>
+#endif
+#ifndef QT_NO_IPV6IFNAME
+#include <net/if.h>
+#endif
+#ifdef QT_LINUXBASE
+#include <arpa/inet.h>
+#endif
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+#include <qstring.h>
+#include <ctype.h>
+#endif
+
+#include <netinet/tcp.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+
+/*
+ Returns a human readable representation of the first \a len
+ characters in \a data.
+*/
+static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
+{
+ if (!data) return "(null)";
+ QByteArray out;
+ for (int i = 0; i < len; ++i) {
+ char c = data[i];
+ if (isprint(c)) {
+ out += c;
+ } else switch (c) {
+ case '\n': out += "\\n"; break;
+ case '\r': out += "\\r"; break;
+ case '\t': out += "\\t"; break;
+ default:
+ QString tmp;
+ tmp.sprintf("\\%o", c);
+ out += tmp.toLatin1();
+ }
+ }
+
+ if (len < maxSize)
+ out += "...";
+
+ return out;
+}
+#endif
+
+static void qt_ignore_sigpipe()
+{
+#ifndef Q_NO_POSIX_SIGNALS
+ // Set to ignore SIGPIPE once only.
+ static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (atom.testAndSetRelaxed(0, 1)) {
+ struct sigaction noaction;
+ memset(&noaction, 0, sizeof(noaction));
+ noaction.sa_handler = SIG_IGN;
+ ::sigaction(SIGPIPE, &noaction, 0);
+ }
+#else
+ // Posix signals are not supported by the underlying platform
+ // so we don't need to ignore sigpipe signal explicitly
+#endif
+}
+
+/*
+ Extracts the port and address from a sockaddr, and stores them in
+ \a port and \a addr if they are non-null.
+*/
+static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr)
+{
+#if !defined(QT_NO_IPV6)
+ if (s->a.sa_family == AF_INET6) {
+ Q_IPV6ADDR tmp;
+ memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp));
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(tmp);
+ *addr = tmpAddress;
+#ifndef QT_NO_IPV6IFNAME
+ char scopeid[IFNAMSIZ];
+ if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) {
+ addr->setScopeId(QLatin1String(scopeid));
+ } else
+#endif
+ addr->setScopeId(QString::number(s->a6.sin6_scope_id));
+ }
+ if (port)
+ *port = ntohs(s->a6.sin6_port);
+ return;
+ }
+#endif
+ if (port)
+ *port = ntohs(s->a4.sin_port);
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr));
+ *addr = tmpAddress;
+ }
+}
+
+/*! \internal
+
+ Creates and returns a new socket descriptor of type \a socketType
+ and \a socketProtocol. Returns -1 on failure.
+*/
+bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
+ QAbstractSocket::NetworkLayerProtocol socketProtocol)
+{
+#ifndef QT_NO_IPV6
+ int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;
+#else
+ Q_UNUSED(socketProtocol);
+ int protocol = AF_INET;
+#endif
+ int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
+
+ int socket = qt_safe_socket(protocol, type, 0);
+
+ if (socket <= 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+ case EAFNOSUPPORT:
+ case EINVAL:
+ setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
+ break;
+ case ENFILE:
+ case EMFILE:
+ case ENOBUFS:
+ case ENOMEM:
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
+ case EACCES:
+ setError(QAbstractSocket::SocketAccessError, AccessErrorString);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ socketDescriptor = socket;
+ return true;
+}
+
+/*
+ Returns the value of the socket option \a opt.
+*/
+int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const
+{
+ Q_Q(const QNativeSocketEngine);
+ if (!q->isValid())
+ return -1;
+
+ int n = -1;
+ int level = SOL_SOCKET; // default
+
+ switch (opt) {
+ case QNativeSocketEngine::ReceiveBufferSocketOption:
+ n = SO_RCVBUF;
+ break;
+ case QNativeSocketEngine::SendBufferSocketOption:
+ n = SO_SNDBUF;
+ break;
+ case QNativeSocketEngine::NonBlockingSocketOption:
+ break;
+ case QNativeSocketEngine::BroadcastSocketOption:
+ break;
+ case QNativeSocketEngine::AddressReusable:
+ n = SO_REUSEADDR;
+ break;
+ case QNativeSocketEngine::BindExclusively:
+ return true;
+ case QNativeSocketEngine::ReceiveOutOfBandData:
+ n = SO_OOBINLINE;
+ break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
+ }
+
+ int v = -1;
+ QT_SOCKOPTLEN_T len = sizeof(v);
+ if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
+ return v;
+
+ return -1;
+}
+
+
+/*
+ Sets the socket option \a opt to \a v.
+*/
+bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v)
+{
+ Q_Q(QNativeSocketEngine);
+ if (!q->isValid())
+ return false;
+
+ int n = 0;
+ int level = SOL_SOCKET; // default
+
+ switch (opt) {
+ case QNativeSocketEngine::ReceiveBufferSocketOption:
+ n = SO_RCVBUF;
+ break;
+ case QNativeSocketEngine::SendBufferSocketOption:
+ n = SO_SNDBUF;
+ break;
+ case QNativeSocketEngine::BroadcastSocketOption:
+ n = SO_BROADCAST;
+ break;
+ case QNativeSocketEngine::NonBlockingSocketOption: {
+ // Make the socket nonblocking.
+#if !defined(Q_OS_VXWORKS)
+ int flags = ::fcntl(socketDescriptor, F_GETFL, 0);
+ if (flags == -1) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed");
+#endif
+ return false;
+ }
+ if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed");
+#endif
+ return false;
+ }
+#else // Q_OS_VXWORKS
+ int onoff = 1;
+
+ if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
+
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed");
+#endif
+ return false;
+ }
+#endif // Q_OS_VXWORKS
+ return true;
+ }
+ case QNativeSocketEngine::AddressReusable:
+#if defined(SO_REUSEPORT)
+ n = SO_REUSEPORT;
+#else
+ n = SO_REUSEADDR;
+#endif
+ break;
+ case QNativeSocketEngine::BindExclusively:
+ return true;
+ case QNativeSocketEngine::ReceiveOutOfBandData:
+ n = SO_OOBINLINE;
+ break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
+ }
+
+ return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0;
+}
+
+bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port)
+{
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor);
+#endif
+
+ struct sockaddr_in sockAddrIPv4;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_in6 sockAddrIPv6;
+
+ if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
+ memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
+ sockAddrIPv6.sin6_family = AF_INET6;
+ sockAddrIPv6.sin6_port = htons(port);
+
+ QString scopeid = addr.scopeId();
+ bool ok;
+ sockAddrIPv6.sin6_scope_id = scopeid.toInt(&ok);
+#ifndef QT_NO_IPV6IFNAME
+ if (!ok)
+ sockAddrIPv6.sin6_scope_id = ::if_nametoindex(scopeid.toLatin1());
+#endif
+ Q_IPV6ADDR ip6 = addr.toIPv6Address();
+ memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));
+
+ sockAddrSize = sizeof(sockAddrIPv6);
+ sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
+ } else
+#if 0
+ {}
+#endif
+#endif
+ if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
+ memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
+ sockAddrIPv4.sin_family = AF_INET;
+ sockAddrIPv4.sin_port = htons(port);
+ sockAddrIPv4.sin_addr.s_addr = htonl(addr.toIPv4Address());
+
+ sockAddrSize = sizeof(sockAddrIPv4);
+ sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
+ } else {
+ // unreachable
+ }
+
+ int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize);
+ if (connectResult == -1) {
+ switch (errno) {
+ case EISCONN:
+ socketState = QAbstractSocket::ConnectedState;
+ break;
+ case ECONNREFUSED:
+ case EINVAL:
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case ETIMEDOUT:
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ break;
+ case EHOSTUNREACH:
+ setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case ENETUNREACH:
+ setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case EADDRINUSE:
+ setError(QAbstractSocket::NetworkError, AddressInuseErrorString);
+ break;
+ case EINPROGRESS:
+ case EALREADY:
+ setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
+ socketState = QAbstractSocket::ConnectingState;
+ break;
+ case EAGAIN:
+ setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
+ case EACCES:
+ case EPERM:
+ setError(QAbstractSocket::SocketAccessError, AccessErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case EAFNOSUPPORT:
+ case EBADF:
+ case EFAULT:
+ case ENOTSOCK:
+ socketState = QAbstractSocket::UnconnectedState;
+ default:
+ break;
+ }
+
+ if (socketState != QAbstractSocket::ConnectedState) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
+ addr.toString().toLatin1().constData(), port,
+ socketState == QAbstractSocket::ConnectingState
+ ? "Connection in progress" : socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
+ addr.toString().toLatin1().constData(), port);
+#endif
+
+ socketState = QAbstractSocket::ConnectedState;
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
+{
+ struct sockaddr_in sockAddrIPv4;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_in6 sockAddrIPv6;
+
+ if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
+ sockAddrIPv6.sin6_family = AF_INET6;
+ sockAddrIPv6.sin6_port = htons(port);
+#ifndef QT_NO_IPV6IFNAME
+ sockAddrIPv6.sin6_scope_id = ::if_nametoindex(address.scopeId().toLatin1().data());
+#else
+ sockAddrIPv6.sin6_scope_id = address.scopeId().toInt();
+#endif
+ Q_IPV6ADDR tmp = address.toIPv6Address();
+ memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
+ sockAddrSize = sizeof(sockAddrIPv6);
+ sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
+ } else
+#endif
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
+ sockAddrIPv4.sin_family = AF_INET;
+ sockAddrIPv4.sin_port = htons(port);
+ sockAddrIPv4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ sockAddrSize = sizeof(sockAddrIPv4);
+ sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
+ } else {
+ // unreachable
+ }
+
+ int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize);
+
+ if (bindResult < 0) {
+ switch(errno) {
+ case EADDRINUSE:
+ setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
+ break;
+ case EACCES:
+ setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
+ break;
+ case EINVAL:
+ setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
+ break;
+ case EADDRNOTAVAIL:
+ setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
+ break;
+ default:
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
+ address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());
+#endif
+
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
+ address.toString().toLatin1().constData(), port);
+#endif
+ socketState = QAbstractSocket::BoundState;
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeListen(int backlog)
+{
+ if (qt_safe_listen(socketDescriptor, backlog) < 0) {
+ switch (errno) {
+ case EADDRINUSE:
+ setError(QAbstractSocket::AddressInUseError,
+ PortInuseErrorString);
+ break;
+ default:
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
+ backlog, socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
+#endif
+
+ socketState = QAbstractSocket::ListeningState;
+ return true;
+}
+
+int QNativeSocketEnginePrivate::nativeAccept()
+{
+ int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
+
+ return acceptedDescriptor;
+}
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
+ int how6,
+ int how4,
+ const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ int level = 0;
+ int sockOpt = 0;
+ void *sockArg;
+ int sockArgSize;
+
+ ip_mreq mreq4;
+#ifndef QT_NO_IPV6
+ ipv6_mreq mreq6;
+
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ sockOpt = how6;
+ sockArg = &mreq6;
+ sockArgSize = sizeof(mreq6);
+ memset(&mreq6, 0, sizeof(mreq6));
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
+ mreq6.ipv6mr_interface = interface.index();
+ } else
+#endif
+ if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ sockOpt = how4;
+ sockArg = &mreq4;
+ sockArgSize = sizeof(mreq4);
+ memset(&mreq4, 0, sizeof(mreq4));
+ mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
+
+ if (interface.isValid()) {
+ QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
+ if (!addressEntries.isEmpty()) {
+ QHostAddress firstIP = addressEntries.first().ip();
+ mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address());
+ } else {
+ d->setError(QAbstractSocket::NetworkError,
+ QNativeSocketEnginePrivate::NetworkUnreachableErrorString);
+ return false;
+ }
+ } else {
+ mreq4.imr_interface.s_addr = INADDR_ANY;
+ }
+ } else {
+ // unreachable
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString);
+ return false;
+ }
+
+ int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize);
+ if (res == -1) {
+ switch (errno) {
+ case ENOPROTOOPT:
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
+ break;
+ case EADDRNOTAVAIL:
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError,
+ QNativeSocketEnginePrivate::AddressNotAvailableErrorString);
+ break;
+ default:
+ d->setError(QAbstractSocket::UnknownSocketError,
+ QNativeSocketEnginePrivate::UnknownSocketErrorString);
+ break;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_JOIN_GROUP,
+#else
+ 0,
+#endif
+ IP_ADD_MEMBERSHIP,
+ groupAddress,
+ interface);
+}
+
+bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_LEAVE_GROUP,
+#else
+ 0,
+#endif
+ IP_DROP_MEMBERSHIP,
+ groupAddress,
+ interface);
+}
+
+QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromIndex(v);
+ }
+#endif
+
+ struct in_addr v = { 0 };
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ if (v.s_addr != 0 && sizeofv >= sizeof(v)) {
+ QHostAddress ipv4(ntohl(v.s_addr));
+ QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
+ for (int i = 0; i < ifaces.count(); ++i) {
+ const QNetworkInterface &iface = ifaces.at(i);
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int j = 0; j < entries.count(); ++j) {
+ const QNetworkAddressEntry &entry = entries.at(j);
+ if (entry.ip() == ipv4)
+ return iface;
+ }
+ }
+ }
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v = iface.index();
+ return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1);
+ }
+#endif
+
+ struct in_addr v;
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int i = 0; i < entries.count(); ++i) {
+ const QNetworkAddressEntry &entry = entries.at(i);
+ const QHostAddress &ip = entry.ip();
+ if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
+ v.s_addr = htonl(ip.toIPv4Address());
+ int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v));
+ if (r != -1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ v.s_addr = INADDR_ANY;
+ return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
+qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
+{
+ int nbytes = 0;
+ // gives shorter than true amounts on Unix domain sockets.
+ qint64 available = 0;
+ if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
+ available = (qint64) nbytes;
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available);
+#endif
+ return available;
+}
+
+bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
+{
+ // Create a sockaddr struct and reset its port number.
+ qt_sockaddr storage;
+ QT_SOCKLEN_T storageSize = sizeof(storage);
+ memset(&storage, 0, storageSize);
+
+ // Peek 0 bytes into the next message. The size of the message may
+ // well be 0, so we can't check recvfrom's return value.
+ ssize_t readBytes;
+ do {
+ char c;
+ readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize);
+ } while (readBytes == -1 && errno == EINTR);
+
+ // If there's no error, or if our buffer was too small, there must be a
+ // pending datagram.
+ bool result = (readBytes != -1) || errno == EMSGSIZE;
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
+ result ? "true" : "false");
+#endif
+ return result;
+}
+
+qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
+{
+ QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
+ ssize_t recvResult = -1;
+
+ for (;;) {
+ // the data written to udpMessagePeekBuffer is discarded, so
+ // this function is still reentrant although it might not look
+ // so.
+ recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(),
+ udpMessagePeekBuffer.size(), MSG_PEEK);
+ if (recvResult == -1 && errno == EINTR)
+ continue;
+
+ if (recvResult != (ssize_t) udpMessagePeekBuffer.size())
+ break;
+
+ udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %i", recvResult);
+#endif
+
+ return qint64(recvResult);
+}
+
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
+ QHostAddress *address, quint16 *port)
+{
+ qt_sockaddr aa;
+ memset(&aa, 0, sizeof(aa));
+ QT_SOCKLEN_T sz;
+ sz = sizeof(aa);
+
+ ssize_t recvFromResult = 0;
+ do {
+ char c;
+ recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
+ 0, &aa.a, &sz);
+ } while (recvFromResult == -1 && errno == EINTR);
+
+ if (recvFromResult == -1) {
+ setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
+ } else if (port || address) {
+ qt_socket_getPortAndAddress(&aa, port, address);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
+ data, qt_prettyDebug(data, qMin(recvFromResult, ssize_t(16)), recvFromResult).data(), maxSize,
+ address ? address->toString().toLatin1().constData() : "(nil)",
+ port ? *port : 0, (qint64) recvFromResult);
+#endif
+
+ return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0);
+}
+
+qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
+ const QHostAddress &host, quint16 port)
+{
+ struct sockaddr_in sockAddrIPv4;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_in6 sockAddrIPv6;
+ if (host.protocol() == QAbstractSocket::IPv6Protocol) {
+ memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
+ sockAddrIPv6.sin6_family = AF_INET6;
+ sockAddrIPv6.sin6_port = htons(port);
+
+ Q_IPV6ADDR tmp = host.toIPv6Address();
+ memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
+ sockAddrSize = sizeof(sockAddrIPv6);
+ sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
+ } else
+#endif
+ if (host.protocol() == QAbstractSocket::IPv4Protocol) {
+ memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
+ sockAddrIPv4.sin_family = AF_INET;
+ sockAddrIPv4.sin_port = htons(port);
+ sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
+ sockAddrSize = sizeof(sockAddrIPv4);
+ sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
+ }
+
+ // ignore the SIGPIPE signal
+ qt_ignore_sigpipe();
+ ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len,
+ 0, sockAddrPtr, sockAddrSize);
+
+ if (sentBytes < 0) {
+ switch (errno) {
+ case EMSGSIZE:
+ setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
+ break;
+ default:
+ setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
+ qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(),
+ port, (qint64) sentBytes);
+#endif
+
+ return qint64(sentBytes);
+}
+
+bool QNativeSocketEnginePrivate::fetchConnectionParameters()
+{
+ localPort = 0;
+ localAddress.clear();
+ peerPort = 0;
+ peerAddress.clear();
+
+ if (socketDescriptor == -1)
+ return false;
+
+ qt_sockaddr sa;
+ QT_SOCKLEN_T sockAddrSize = sizeof(sa);
+
+ // Determine local address
+ memset(&sa, 0, sizeof(sa));
+ if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(&sa, &localPort, &localAddress);
+
+ // Determine protocol family
+ switch (sa.a.sa_family) {
+ case AF_INET:
+ socketProtocol = QAbstractSocket::IPv4Protocol;
+ break;
+#if !defined (QT_NO_IPV6)
+ case AF_INET6:
+ socketProtocol = QAbstractSocket::IPv6Protocol;
+ break;
+#endif
+ default:
+ socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ break;
+ }
+
+ } else if (errno == EBADF) {
+ setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
+ return false;
+ }
+
+ // Determine the remote address
+ if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize))
+ qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress);
+
+ // Determine the socket type (UDP/TCP)
+ int value = 0;
+ QT_SOCKOPTLEN_T valueSize = sizeof(int);
+ if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
+ if (value == SOCK_STREAM)
+ socketType = QAbstractSocket::TcpSocket;
+ else if (value == SOCK_DGRAM)
+ socketType = QAbstractSocket::UdpSocket;
+ else
+ socketType = QAbstractSocket::UnknownSocketType;
+ }
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString socketProtocolStr = "UnknownProtocol";
+ if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol";
+ else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol";
+
+ QString socketTypeStr = "UnknownSocketType";
+ if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket";
+ else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket";
+
+ qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
+ " peer == %s:%i, socket == %s - %s",
+ localAddress.toString().toLatin1().constData(), localPort,
+ peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
+ socketProtocolStr.toLatin1().constData());
+#endif
+ return true;
+}
+
+void QNativeSocketEnginePrivate::nativeClose()
+{
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEngine::nativeClose()");
+#endif
+
+ qt_safe_close(socketDescriptor);
+}
+
+qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
+{
+ Q_Q(QNativeSocketEngine);
+
+ // ignore the SIGPIPE signal
+ qt_ignore_sigpipe();
+
+ ssize_t writtenBytes;
+ writtenBytes = qt_safe_write(socketDescriptor, data, len);
+
+ if (writtenBytes < 0) {
+ switch (errno) {
+ case EPIPE:
+ case ECONNRESET:
+ writtenBytes = -1;
+ setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
+ q->close();
+ break;
+ case EAGAIN:
+ writtenBytes = 0;
+ break;
+ case EMSGSIZE:
+ setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
+ break;
+ default:
+ break;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i",
+ data, qt_prettyDebug(data, qMin((int) len, 16),
+ (int) len).data(), len, (int) writtenBytes);
+#endif
+
+ return qint64(writtenBytes);
+}
+/*
+*/
+qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
+{
+ Q_Q(QNativeSocketEngine);
+ if (!q->isValid()) {
+ qWarning("QNativeSocketEngine::nativeRead: Invalid socket");
+ return -1;
+ }
+
+ ssize_t r = 0;
+ r = qt_safe_read(socketDescriptor, data, maxSize);
+
+ if (r < 0) {
+ r = -1;
+ switch (errno) {
+#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+ // No data was available for reading
+ r = -2;
+ break;
+ case EBADF:
+ case EINVAL:
+ case EIO:
+ //error string is now set in read(), not here in nativeRead()
+ break;
+ case ECONNRESET:
+#if defined(Q_OS_VXWORKS)
+ case ESHUTDOWN:
+#endif
+ r = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i",
+ data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),
+ maxSize, r);
+#endif
+
+ return qint64(r);
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+{
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(socketDescriptor, &fds);
+
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ int retval;
+ if (selectForRead)
+ retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
+ else
+ retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
+
+ return retval;
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const
+{
+ fd_set fdread;
+ FD_ZERO(&fdread);
+ if (checkRead)
+ FD_SET(socketDescriptor, &fdread);
+
+ fd_set fdwrite;
+ FD_ZERO(&fdwrite);
+ if (checkWrite)
+ FD_SET(socketDescriptor, &fdwrite);
+
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ int ret;
+ ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
+
+ if (ret <= 0)
+ return ret;
+ *selectForRead = FD_ISSET(socketDescriptor, &fdread);
+ *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
new file mode 100644
index 0000000000..940569aa7b
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -0,0 +1,1439 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include "qnativesocketengine_p.h"
+
+#include <qabstracteventdispatcher.h>
+#include <qsocketnotifier.h>
+#include <qdebug.h>
+#include <qdatetime.h>
+#include <qnetworkinterface.h>
+
+//#define QNATIVESOCKETENGINE_DEBUG
+#if defined(QNATIVESOCKETENGINE_DEBUG)
+# include <qstring.h>
+# include <qbytearray.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QNATIVESOCKETENGINE_DEBUG)
+
+void verboseWSErrorDebug(int r)
+{
+ switch (r) {
+ case WSANOTINITIALISED : qDebug("WSA error : WSANOTINITIALISED"); break;
+ case WSAEINTR: qDebug("WSA error : WSAEINTR"); break;
+ case WSAEBADF: qDebug("WSA error : WSAEBADF"); break;
+ case WSAEACCES: qDebug("WSA error : WSAEACCES"); break;
+ case WSAEFAULT: qDebug("WSA error : WSAEFAULT"); break;
+ case WSAEINVAL: qDebug("WSA error : WSAEINVAL"); break;
+ case WSAEMFILE: qDebug("WSA error : WSAEMFILE"); break;
+ case WSAEWOULDBLOCK: qDebug("WSA error : WSAEWOULDBLOCK"); break;
+ case WSAEINPROGRESS: qDebug("WSA error : WSAEINPROGRESS"); break;
+ case WSAEALREADY: qDebug("WSA error : WSAEALREADY"); break;
+ case WSAENOTSOCK: qDebug("WSA error : WSAENOTSOCK"); break;
+ case WSAEDESTADDRREQ: qDebug("WSA error : WSAEDESTADDRREQ"); break;
+ case WSAEMSGSIZE: qDebug("WSA error : WSAEMSGSIZE"); break;
+ case WSAEPROTOTYPE: qDebug("WSA error : WSAEPROTOTYPE"); break;
+ case WSAENOPROTOOPT: qDebug("WSA error : WSAENOPROTOOPT"); break;
+ case WSAEPROTONOSUPPORT: qDebug("WSA error : WSAEPROTONOSUPPORT"); break;
+ case WSAESOCKTNOSUPPORT: qDebug("WSA error : WSAESOCKTNOSUPPORT"); break;
+ case WSAEOPNOTSUPP: qDebug("WSA error : WSAEOPNOTSUPP"); break;
+ case WSAEPFNOSUPPORT: qDebug("WSA error : WSAEPFNOSUPPORT"); break;
+ case WSAEAFNOSUPPORT: qDebug("WSA error : WSAEAFNOSUPPORT"); break;
+ case WSAEADDRINUSE: qDebug("WSA error : WSAEADDRINUSE"); break;
+ case WSAEADDRNOTAVAIL: qDebug("WSA error : WSAEADDRNOTAVAIL"); break;
+ case WSAENETDOWN: qDebug("WSA error : WSAENETDOWN"); break;
+ case WSAENETUNREACH: qDebug("WSA error : WSAENETUNREACH"); break;
+ case WSAENETRESET: qDebug("WSA error : WSAENETRESET"); break;
+ case WSAECONNABORTED: qDebug("WSA error : WSAECONNABORTED"); break;
+ case WSAECONNRESET: qDebug("WSA error : WSAECONNRESET"); break;
+ case WSAENOBUFS: qDebug("WSA error : WSAENOBUFS"); break;
+ case WSAEISCONN: qDebug("WSA error : WSAEISCONN"); break;
+ case WSAENOTCONN: qDebug("WSA error : WSAENOTCONN"); break;
+ case WSAESHUTDOWN: qDebug("WSA error : WSAESHUTDOWN"); break;
+ case WSAETOOMANYREFS: qDebug("WSA error : WSAETOOMANYREFS"); break;
+ case WSAETIMEDOUT: qDebug("WSA error : WSAETIMEDOUT"); break;
+ case WSAECONNREFUSED: qDebug("WSA error : WSAECONNREFUSED"); break;
+ case WSAELOOP: qDebug("WSA error : WSAELOOP"); break;
+ case WSAENAMETOOLONG: qDebug("WSA error : WSAENAMETOOLONG"); break;
+ case WSAEHOSTDOWN: qDebug("WSA error : WSAEHOSTDOWN"); break;
+ case WSAEHOSTUNREACH: qDebug("WSA error : WSAEHOSTUNREACH"); break;
+ case WSAENOTEMPTY: qDebug("WSA error : WSAENOTEMPTY"); break;
+ case WSAEPROCLIM: qDebug("WSA error : WSAEPROCLIM"); break;
+ case WSAEUSERS: qDebug("WSA error : WSAEUSERS"); break;
+ case WSAEDQUOT: qDebug("WSA error : WSAEDQUOT"); break;
+ case WSAESTALE: qDebug("WSA error : WSAESTALE"); break;
+ case WSAEREMOTE: qDebug("WSA error : WSAEREMOTE"); break;
+ case WSAEDISCON: qDebug("WSA error : WSAEDISCON"); break;
+ default: qDebug("WSA error : Unknown"); break;
+ }
+ qErrnoWarning(r, "more details");
+}
+
+/*
+ Returns a human readable representation of the first \a len
+ characters in \a data.
+*/
+static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
+{
+ if (!data) return "(null)";
+ QByteArray out;
+ for (int i = 0; i < len; ++i) {
+ char c = data[i];
+ if (isprint(int(uchar(c)))) {
+ out += c;
+ } else switch (c) {
+ case '\n': out += "\\n"; break;
+ case '\r': out += "\\r"; break;
+ case '\t': out += "\\t"; break;
+ default:
+ QString tmp;
+ tmp.sprintf("\\%o", c);
+ out += tmp.toLatin1().constData();
+ }
+ }
+
+ if (len < maxLength)
+ out += "...";
+
+ return out;
+}
+
+
+#define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x);
+
+#else
+
+#define WS_ERROR_DEBUG(x) Q_UNUSED(x)
+
+#endif
+
+#ifndef AF_INET6
+#define AF_INET6 23 /* Internetwork Version 6 */
+#endif
+
+#ifndef SO_EXCLUSIVEADDRUSE
+#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */
+#endif
+
+//###
+#define QT_SOCKLEN_T int
+#define QT_SOCKOPTLEN_T int
+
+
+/*
+ Extracts the port and address from a sockaddr, and stores them in
+ \a port and \a addr if they are non-null.
+*/
+static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address)
+{
+#if !defined (QT_NO_IPV6)
+ if (sa->a.sa_family == AF_INET6) {
+ const qt_sockaddr_in6 *sa6 = &sa->a6;
+ Q_IPV6ADDR tmp;
+ for (int i = 0; i < 16; ++i)
+ tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i];
+ QHostAddress a;
+ a.setAddress(tmp);
+ if (address)
+ *address = a;
+ if (port)
+ WSANtohs(socketDescriptor, sa6->sin6_port, port);
+ } else
+#endif
+ if (sa->a.sa_family == AF_INET) {
+ const sockaddr_in *sa4 = &sa->a4;
+ unsigned long addr;
+ WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr);
+ QHostAddress a;
+ a.setAddress(addr);
+ if (address)
+ *address = a;
+ if (port)
+ WSANtohs(socketDescriptor, sa4->sin_port, port);
+ }
+}
+
+
+/*! \internal
+
+ Sets the port and address to a sockaddr. Requires that sa point to the IPv6 struct if the address is IPv6.
+*/
+static inline void qt_socket_setPortAndAddress(SOCKET socketDescriptor, sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6,
+ quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize)
+{
+#if !defined(QT_NO_IPV6)
+ if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6));
+ sockAddrIPv6->sin6_family = AF_INET6;
+ sockAddrIPv6->sin6_scope_id = address.scopeId().toInt();
+ WSAHtons(socketDescriptor, port, &(sockAddrIPv6->sin6_port));
+ Q_IPV6ADDR tmp = address.toIPv6Address();
+ memcpy(&(sockAddrIPv6->sin6_addr.qt_s6_addr), &tmp, sizeof(tmp));
+ *sockAddrSize = sizeof(qt_sockaddr_in6);
+ *sockAddrPtr = (struct sockaddr *) sockAddrIPv6;
+ } else
+#endif
+ if (address.protocol() == QAbstractSocket::IPv4Protocol
+ || address.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) {
+ memset(sockAddrIPv4, 0, sizeof(sockaddr_in));
+ sockAddrIPv4->sin_family = AF_INET;
+ WSAHtons(socketDescriptor, port, &(sockAddrIPv4->sin_port));
+ WSAHtonl(socketDescriptor, address.toIPv4Address(), &(sockAddrIPv4->sin_addr.s_addr));
+ *sockAddrSize = sizeof(sockaddr_in);
+ *sockAddrPtr = (struct sockaddr *) sockAddrIPv4;
+ } else {
+ // unreachable
+ }
+}
+
+/*! \internal
+
+*/
+static inline QAbstractSocket::SocketType qt_socket_getType(int socketDescriptor)
+{
+ int value = 0;
+ QT_SOCKLEN_T valueSize = sizeof(value);
+ if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, (char *) &value, &valueSize) != 0) {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ } else {
+ if (value == SOCK_STREAM)
+ return QAbstractSocket::TcpSocket;
+ else if (value == SOCK_DGRAM)
+ return QAbstractSocket::UdpSocket;
+ }
+ return QAbstractSocket::UnknownSocketType;
+}
+
+/*! \internal
+
+*/
+static inline int qt_socket_getMaxMsgSize(int socketDescriptor)
+{
+ int value = 0;
+ QT_SOCKLEN_T valueSize = sizeof(value);
+ if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *) &value, &valueSize) != 0) {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ }
+ return value;
+}
+
+QWindowsSockInit::QWindowsSockInit()
+: version(0)
+{
+ //### should we try for 2.2 on all platforms ??
+ WSAData wsadata;
+
+ // IPv6 requires Winsock v2.0 or better.
+ if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
+ qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
+ } else {
+ version = 0x20;
+ }
+}
+
+QWindowsSockInit::~QWindowsSockInit()
+{
+ WSACleanup();
+}
+
+// MS Transport Provider IOCTL to control
+// reporting PORT_UNREACHABLE messages
+// on UDP sockets via recv/WSARecv/etc.
+// Path TRUE in input buffer to enable (default if supported),
+// FALSE to disable.
+#ifndef SIO_UDP_CONNRESET
+# ifndef IOC_VENDOR
+# define IOC_VENDOR 0x18000000
+# endif
+# ifndef _WSAIOW
+# define _WSAIOW(x,y) (IOC_IN|(x)|(y))
+# endif
+# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+#endif
+
+bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol socketProtocol)
+{
+
+ //### no ip6 support on winsocket 1.1 but we will try not to use this !!!!!!!!!!!!1
+ /*
+ if (winsockVersion < 0x20 && socketProtocol == QAbstractSocket::IPv6Protocol) {
+ //### no ip6 support
+ return -1;
+ }
+ */
+
+ int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;
+ int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
+ // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking
+ // and recomends alwasy doing it for cross windows version comapablity.
+ SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
+
+ if (socket == INVALID_SOCKET) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSANOTINITIALISED:
+ //###
+ break;
+ case WSAEAFNOSUPPORT:
+ case WSAESOCKTNOSUPPORT:
+ case WSAEPROTOTYPE:
+ case WSAEINVAL:
+ setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
+ break;
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+#if !defined(Q_OS_WINCE)
+ if (socketType == QAbstractSocket::UdpSocket) {
+ // enable new behavior using
+ // SIO_UDP_CONNRESET
+ DWORD dwBytesReturned = 0;
+ int bNewBehavior = 1;
+ if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
+ NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) {
+ // not to worry isBogusUdpReadNotification() should handle this otherwise
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ }
+ }
+#endif
+
+ socketDescriptor = socket;
+ return true;
+
+}
+
+/*! \internal
+
+ Returns the value of the socket option \a opt.
+*/
+int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const
+{
+ Q_Q(const QNativeSocketEngine);
+ if (!q->isValid())
+ return -1;
+
+ int n = -1;
+ int level = SOL_SOCKET; // default
+
+ switch (opt) {
+ case QNativeSocketEngine::ReceiveBufferSocketOption:
+ n = SO_RCVBUF;
+ break;
+ case QNativeSocketEngine::SendBufferSocketOption:
+ n = SO_SNDBUF;
+ break;
+ case QNativeSocketEngine::BroadcastSocketOption:
+ n = SO_BROADCAST;
+ break;
+ case QNativeSocketEngine::NonBlockingSocketOption: {
+ unsigned long buf = 0;
+ if (WSAIoctl(socketDescriptor, FIONBIO, 0,0, &buf, sizeof(buf), 0,0,0) == 0)
+ return buf;
+ else
+ return -1;
+ break;
+ }
+ case QNativeSocketEngine::AddressReusable:
+ n = SO_REUSEADDR;
+ break;
+ case QNativeSocketEngine::BindExclusively:
+ n = SO_EXCLUSIVEADDRUSE;
+ break;
+ case QNativeSocketEngine::ReceiveOutOfBandData:
+ n = SO_OOBINLINE;
+ break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
+ }
+
+ int v = -1;
+ QT_SOCKOPTLEN_T len = sizeof(v);
+ if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
+ return v;
+ return -1;
+}
+
+
+/*! \internal
+ Sets the socket option \a opt to \a v.
+*/
+bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v)
+{
+ Q_Q(const QNativeSocketEngine);
+ if (!q->isValid())
+ return false;
+
+ int n = 0;
+ int level = SOL_SOCKET; // default
+
+ switch (opt) {
+ case QNativeSocketEngine::ReceiveBufferSocketOption:
+ n = SO_RCVBUF;
+ break;
+ case QNativeSocketEngine::SendBufferSocketOption:
+ n = SO_SNDBUF;
+ break;
+ case QNativeSocketEngine::BroadcastSocketOption:
+ n = SO_BROADCAST;
+ break;
+ case QNativeSocketEngine::NonBlockingSocketOption:
+ {
+ unsigned long buf = v;
+ unsigned long outBuf;
+ DWORD sizeWritten = 0;
+ if (::WSAIoctl(socketDescriptor, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) == SOCKET_ERROR) {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ return false;
+ }
+ return true;
+ break;
+ }
+ case QNativeSocketEngine::AddressReusable:
+ n = SO_REUSEADDR;
+ break;
+ case QNativeSocketEngine::BindExclusively:
+ n = SO_EXCLUSIVEADDRUSE;
+ break;
+ case QNativeSocketEngine::ReceiveOutOfBandData:
+ n = SO_OOBINLINE;
+ break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
+ }
+
+ if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Fetches information about both ends of the connection: whatever is
+ available.
+*/
+bool QNativeSocketEnginePrivate::fetchConnectionParameters()
+{
+ localPort = 0;
+ localAddress.clear();
+ peerPort = 0;
+ peerAddress.clear();
+
+ if (socketDescriptor == -1)
+ return false;
+
+ qt_sockaddr sa;
+ QT_SOCKLEN_T sockAddrSize = sizeof(sa);
+
+ // Determine local address
+ memset(&sa, 0, sizeof(sa));
+ if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, &sa, &localPort, &localAddress);
+ // Determine protocol family
+ switch (sa.a.sa_family) {
+ case AF_INET:
+ socketProtocol = QAbstractSocket::IPv4Protocol;
+ break;
+#if !defined (QT_NO_IPV6)
+ case AF_INET6:
+ socketProtocol = QAbstractSocket::IPv6Protocol;
+ break;
+#endif
+ default:
+ socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ break;
+ }
+ } else {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ if (err == WSAENOTSOCK) {
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ InvalidSocketErrorString);
+ return false;
+ }
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, &sa, &peerPort, &peerAddress);
+ } else {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ }
+
+ socketType = qt_socket_getType(socketDescriptor);
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString socketProtocolStr = "UnknownProtocol";
+ if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol";
+ else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol";
+
+ QString socketTypeStr = "UnknownSocketType";
+ if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket";
+ else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket";
+
+ qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() localAddress == %s, localPort = %i, peerAddress == %s, peerPort = %i, socketProtocol == %s, socketType == %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort, socketProtocolStr.toLatin1().constData(), socketTypeStr.toLatin1().constData());
+#endif
+
+ return true;
+}
+
+
+bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quint16 port)
+{
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeConnect() to %s :: %i", address.toString().toLatin1().constData(), port);
+#endif
+
+ struct sockaddr_in sockAddrIPv4;
+ qt_sockaddr_in6 sockAddrIPv6;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+ qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+
+ forever {
+ int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0);
+ if (connectResult == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+
+ switch (err) {
+ case WSANOTINITIALISED:
+ //###
+ break;
+ case WSAEISCONN:
+ socketState = QAbstractSocket::ConnectedState;
+ break;
+ case WSAEWOULDBLOCK: {
+ // If WSAConnect returns WSAEWOULDBLOCK on the second
+ // connection attempt, we have to check SO_ERROR's
+ // value to detect ECONNREFUSED. If we don't get
+ // ECONNREFUSED, we'll have to treat it as an
+ // unfinished operation.
+ int value = 0;
+ QT_SOCKLEN_T valueSize = sizeof(value);
+ if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
+ if (value == WSAECONNREFUSED) {
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ if (value == WSAETIMEDOUT) {
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ if (value == WSAEHOSTUNREACH) {
+ setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ if (value == WSAEADDRNOTAVAIL) {
+ setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+ }
+ // fall through
+ }
+ case WSAEINPROGRESS:
+ setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
+ socketState = QAbstractSocket::ConnectingState;
+ break;
+ case WSAEADDRINUSE:
+ setError(QAbstractSocket::NetworkError, AddressInuseErrorString);
+ break;
+ case WSAECONNREFUSED:
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case WSAETIMEDOUT:
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ break;
+ case WSAEACCES:
+ setError(QAbstractSocket::SocketAccessError, AccessErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case WSAEHOSTUNREACH:
+ setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case WSAENETUNREACH:
+ setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ case WSAEINVAL:
+ case WSAEALREADY:
+ setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
+ break;
+ default:
+ break;
+ }
+ if (socketState != QAbstractSocket::ConnectedState) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
+ address.toString().toLatin1().constData(), port,
+ socketState == QAbstractSocket::ConnectingState
+ ? "Connection in progress" : socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+ }
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
+ address.toString().toLatin1().constData(), port);
+#endif
+
+ socketState = QAbstractSocket::ConnectedState;
+ return true;
+}
+
+
+bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port)
+{
+ QHostAddress address = a;
+ switch (address.protocol()) {
+ case QAbstractSocket::IPv6Protocol:
+ if (address.toIPv6Address()[0] == 0xff) {
+ // binding to a multicast address
+ address = QHostAddress(QHostAddress::AnyIPv6);
+ }
+ break;
+ case QAbstractSocket::IPv4Protocol:
+ if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) {
+ // binding to a multicast address
+ address = QHostAddress(QHostAddress::Any);
+ }
+ break;
+ default:
+ break;
+ }
+
+ struct sockaddr_in sockAddrIPv4;
+ qt_sockaddr_in6 sockAddrIPv6;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+ qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+
+
+ int bindResult = ::bind(socketDescriptor, sockAddrPtr, sockAddrSize);
+ if (bindResult == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSANOTINITIALISED:
+ //###
+ break;
+ case WSAEADDRINUSE:
+ case WSAEINVAL:
+ setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
+ break;
+ case WSAEACCES:
+ setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
+ break;
+ case WSAEADDRNOTAVAIL:
+ setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
+ break;
+ default:
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
+ address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());
+#endif
+
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
+ address.toString().toLatin1().constData(), port);
+#endif
+ socketState = QAbstractSocket::BoundState;
+ return true;
+}
+
+
+bool QNativeSocketEnginePrivate::nativeListen(int backlog)
+{
+ if (::listen(socketDescriptor, backlog) == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSANOTINITIALISED:
+ //###
+ break;
+ case WSAEADDRINUSE:
+ setError(QAbstractSocket::AddressInUseError,
+ PortInuseErrorString);
+ break;
+ default:
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
+ backlog, socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
+#endif
+
+ socketState = QAbstractSocket::ListeningState;
+ return true;
+}
+
+int QNativeSocketEnginePrivate::nativeAccept()
+{
+ int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
+ if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
+ // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
+ // with the same attributes as the listening socket including the current
+ // WSAAsyncSelect(). To be able to change the socket to blocking mode the
+ // WSAAsyncSelect() call must be cancled.
+ QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
+ n.setEnabled(true);
+ n.setEnabled(false);
+ }
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
+#endif
+ return acceptedDescriptor;
+}
+
+static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
+ int how6,
+ int how4,
+ const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ int level = 0;
+ int sockOpt = 0;
+ char *sockArg;
+ int sockArgSize;
+
+ struct ip_mreq mreq4;
+#ifndef QT_NO_IPV6
+ struct ipv6_mreq mreq6;
+
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ sockOpt = how6;
+ sockArg = reinterpret_cast<char *>(&mreq6);
+ sockArgSize = sizeof(mreq6);
+ memset(&mreq6, 0, sizeof(mreq6));
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
+ mreq6.ipv6mr_interface = iface.index();
+ } else
+#endif
+ if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ sockOpt = how4;
+ sockArg = reinterpret_cast<char *>(&mreq4);
+ sockArgSize = sizeof(mreq4);
+ memset(&mreq4, 0, sizeof(mreq4));
+ mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
+
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> addressEntries = iface.addressEntries();
+ if (!addressEntries.isEmpty()) {
+ QHostAddress firstIP = addressEntries.first().ip();
+ mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address());
+ } else {
+ d->setError(QAbstractSocket::NetworkError,
+ QNativeSocketEnginePrivate::NetworkUnreachableErrorString);
+ return false;
+ }
+ } else {
+ mreq4.imr_interface.s_addr = INADDR_ANY;
+ }
+ } else {
+ // unreachable
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString);
+ return false;
+ }
+
+ int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize);
+ if (res == -1) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
+ return false;
+ }
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_JOIN_GROUP,
+#else
+ 0,
+#endif
+ IP_ADD_MEMBERSHIP,
+ groupAddress,
+ iface);
+}
+
+bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_LEAVE_GROUP,
+#else
+ 0,
+#endif
+ IP_DROP_MEMBERSHIP,
+ groupAddress,
+ iface);
+}
+
+QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromIndex(v);
+ }
+#endif
+
+ struct in_addr v;
+ v.s_addr = 0;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) {
+ QHostAddress ipv4(ntohl(v.s_addr));
+ QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
+ for (int i = 0; i < ifaces.count(); ++i) {
+ const QNetworkInterface &iface = ifaces.at(i);
+ if (!(iface.flags() & QNetworkInterface::CanMulticast))
+ continue;
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int j = 0; j < entries.count(); ++j) {
+ const QNetworkAddressEntry &entry = entries.at(j);
+ if (entry.ip() == ipv4)
+ return iface;
+ }
+ }
+ }
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v = iface.isValid() ? iface.index() : 0;
+ return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
+ }
+#endif
+
+ struct in_addr v;
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int i = 0; i < entries.count(); ++i) {
+ const QNetworkAddressEntry &entry = entries.at(i);
+ const QHostAddress &ip = entry.ip();
+ if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
+ v.s_addr = htonl(ip.toIPv4Address());
+ int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v));
+ if (r != -1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ v.s_addr = INADDR_ANY;
+ return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
+}
+
+qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
+{
+ unsigned long nbytes = 0;
+ unsigned long dummy = 0;
+ DWORD sizeWritten = 0;
+ if (::WSAIoctl(socketDescriptor, FIONREAD, &dummy, sizeof(dummy), &nbytes, sizeof(nbytes), &sizeWritten, 0,0) == SOCKET_ERROR) {
+ WS_ERROR_DEBUG(WSAGetLastError());
+ return -1;
+ }
+
+ // ioctlsocket sometimes reports 1 byte available for datagrams
+ // while the following recvfrom returns -1 and claims connection
+ // was reset (udp is connectionless). so we peek one byte to
+ // catch this case and return 0 bytes available if recvfrom
+ // fails.
+ if (nbytes == 1 && socketType == QAbstractSocket::UdpSocket) {
+ char c;
+ WSABUF buf;
+ buf.buf = &c;
+ buf.len = sizeof(c);
+ DWORD flags = MSG_PEEK;
+ if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR)
+ return 0;
+ }
+ return nbytes;
+}
+
+
+bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
+{
+#if !defined(Q_OS_WINCE)
+ // Create a sockaddr struct and reset its port number.
+ qt_sockaddr storage;
+ QT_SOCKLEN_T storageSize = sizeof(storage);
+ memset(&storage, 0, storageSize);
+
+ bool result = false;
+
+ // Peek 0 bytes into the next message. The size of the message may
+ // well be 0, so we check if there was a sender.
+ char c;
+ WSABUF buf;
+ buf.buf = &c;
+ buf.len = sizeof(c);
+ DWORD available = 0;
+ DWORD flags = MSG_PEEK;
+ int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, &storage.a, &storageSize,0,0);
+ int err = WSAGetLastError();
+ if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) {
+ WS_ERROR_DEBUG(err);
+ if (err == WSAECONNRESET) {
+ // Discard error message to prevent QAbstractSocket from
+ // getting this message repeatedly after reenabling the
+ // notifiers.
+ flags = 0;
+ ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags,
+ &storage.a, &storageSize, 0, 0);
+ }
+ } else {
+ // If there's no error, or if our buffer was too small, there must be
+ // a pending datagram.
+ result = true;
+ }
+
+#else // Q_OS_WINCE
+ bool result = false;
+ fd_set readS;
+ FD_ZERO(&readS);
+ FD_SET((SOCKET)socketDescriptor, &readS);
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 5000;
+ int available = ::select(1, &readS, 0, 0, &timeout);
+ result = available > 0 ? true : false;
+#endif
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
+ result ? "true" : "false");
+#endif
+ return result;
+}
+
+
+qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
+{
+ qint64 ret = -1;
+#if !defined(Q_OS_WINCE)
+ int recvResult = 0;
+ DWORD flags;
+ DWORD bufferCount = 5;
+ WSABUF * buf = 0;
+ for (;;) {
+ // the data written to udpMessagePeekBuffer is discarded, so
+ // this function is still reentrant although it might not look
+ // so.
+ static char udpMessagePeekBuffer[8192];
+
+ buf = new WSABUF[bufferCount];
+ for (DWORD i=0; i<bufferCount; i++) {
+ buf[i].buf = udpMessagePeekBuffer;
+ buf[i].len = sizeof(udpMessagePeekBuffer);
+ }
+ flags = MSG_PEEK;
+ DWORD bytesRead = 0;
+ recvResult = ::WSARecv(socketDescriptor, buf, bufferCount, &bytesRead, &flags, 0,0);
+ int err = WSAGetLastError();
+ if (recvResult != SOCKET_ERROR) {
+ ret = qint64(bytesRead);
+ break;
+ } else if (recvResult == SOCKET_ERROR && err == WSAEMSGSIZE) {
+ bufferCount += 5;
+ delete[] buf;
+ } else if (recvResult == SOCKET_ERROR) {
+ WS_ERROR_DEBUG(err);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (buf)
+ delete[] buf;
+
+#else // Q_OS_WINCE
+ DWORD size = -1;
+ DWORD bytesReturned;
+ int ioResult = WSAIoctl(socketDescriptor, FIONREAD, 0,0, &size, sizeof(size), &bytesReturned, 0, 0);
+ if (ioResult == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ } else {
+ ret = qint64(size);
+ }
+#endif
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %li", ret);
+#endif
+
+ return ret;
+}
+
+
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength,
+ QHostAddress *address, quint16 *port)
+{
+ qint64 ret = 0;
+
+ qt_sockaddr aa;
+ memset(&aa, 0, sizeof(aa));
+ QT_SOCKLEN_T sz;
+ sz = sizeof(aa);
+
+ WSABUF buf;
+ buf.buf = data;
+ buf.len = maxLength;
+#if !defined(Q_OS_WINCE)
+ buf.buf = data;
+ buf.len = maxLength;
+#else
+ char tmpChar;
+ buf.buf = data ? data : &tmpChar;
+ buf.len = maxLength;
+#endif
+
+ DWORD flags = 0;
+ DWORD bytesRead = 0;
+ int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, &aa.a, &sz,0,0);
+ if (wsaRet == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ if (err == WSAEMSGSIZE) {
+ // it is ok the buffer was to small if bytesRead is larger than
+ // maxLength then assume bytes read is really maxLenth
+ ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead);
+ } else {
+ WS_ERROR_DEBUG(err);
+ setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
+ ret = -1;
+ }
+ } else {
+ ret = qint64(bytesRead);
+ }
+
+ qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address);
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li",
+ data, qt_prettyDebug(data, qMin<qint64>(ret, 16), ret).data(), maxLength,
+ address ? address->toString().toLatin1().constData() : "(nil)",
+ port ? *port : 0, ret);
+#endif
+
+ return ret;
+}
+
+
+qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
+ const QHostAddress &address, quint16 port)
+{
+ qint64 ret = -1;
+ struct sockaddr_in sockAddrIPv4;
+ qt_sockaddr_in6 sockAddrIPv6;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
+
+ qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+
+ WSABUF buf;
+#if !defined(Q_OS_WINCE)
+ buf.buf = len ? (char*)data : 0;
+#else
+ char tmp;
+ buf.buf = len ? (char*)data : &tmp;
+#endif
+ buf.len = len;
+ DWORD flags = 0;
+ DWORD bytesSent = 0;
+ if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSAEMSGSIZE:
+ setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
+ break;
+ default:
+ setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
+ break;
+ }
+ ret = -1;
+ } else {
+ ret = qint64(bytesSent);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %li, \"%s\", %i) == %li", data,
+ qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), 0, address.toString().toLatin1().constData(),
+ port, ret);
+#endif
+
+ return ret;
+}
+
+
+qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
+{
+ Q_Q(QNativeSocketEngine);
+ qint64 ret = 0;
+ qint64 bytesToSend = len;
+
+ for (;;) {
+ WSABUF buf;
+ buf.buf = (char*)data + ret;
+ buf.len = bytesToSend;
+ DWORD flags = 0;
+ DWORD bytesWritten = 0;
+
+ int socketRet = ::WSASend(socketDescriptor, &buf, 1, &bytesWritten, flags, 0,0);
+
+ ret += qint64(bytesWritten);
+
+ int err;
+ if (socketRet != SOCKET_ERROR) {
+ if (ret == len)
+ break;
+ else
+ continue;
+ } else if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) {
+ break;
+ } else if (err == WSAENOBUFS) {
+ // this function used to not send more than 49152 per call to WSASendTo
+ // to avoid getting a WSAENOBUFS. However this is a performance regression
+ // and we think it only appears with old windows versions. We now handle the
+ // WSAENOBUFS and hope it never appears anyway.
+ // just go on, the next loop run we will try a smaller number
+ } else {
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSAECONNRESET:
+ case WSAECONNABORTED:
+ ret = -1;
+ setError(QAbstractSocket::NetworkError, WriteErrorString);
+ q->close();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ // for next send:
+ bytesToSend = qMin<qint64>(49152, len - ret);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %li) == %li",
+ data, qt_prettyDebug(data, qMin((int)ret, 16), (int)ret).data(), (int)len, (int)ret);
+#endif
+
+ return ret;
+}
+
+qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
+{
+ qint64 ret = -1;
+ WSABUF buf;
+ buf.buf = data;
+ buf.len = maxLength;
+ DWORD flags = 0;
+ DWORD bytesRead = 0;
+#if defined(Q_OS_WINCE)
+ WSASetLastError(0);
+#endif
+ if (::WSARecv(socketDescriptor, &buf, 1, &bytesRead, &flags, 0,0) == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSAEWOULDBLOCK:
+ ret = -2;
+ break;
+ case WSAEBADF:
+ case WSAEINVAL:
+ //error string is now set in read(), not here in nativeRead()
+ break;
+ case WSAECONNRESET:
+ case WSAECONNABORTED:
+ // for tcp sockets this will be handled in QNativeSocketEngine::read
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ ret = -2;
+ else
+ ret = qint64(bytesRead);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ if (ret != -2) {
+ qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %l) == %li",
+ data, qt_prettyDebug(data, qMin((int)bytesRead, 16), (int)bytesRead).data(), (int)maxLength, (int)ret);
+ } else {
+ qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %l) == -2 (WOULD BLOCK)",
+ data, int(maxLength));
+ }
+#endif
+
+ return ret;
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+{
+ bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
+ if (readEnabled)
+ readNotifier->setEnabled(false);
+
+ fd_set fds;
+
+ int ret = 0;
+
+ memset(&fds, 0, sizeof(fd_set));
+ fds.fd_count = 1;
+ fds.fd_array[0] = (SOCKET)socketDescriptor;
+
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ if (selectForRead) {
+ ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv);
+ } else {
+ // select for write
+
+ // Windows needs this to report errors when connecting a socket ...
+ fd_set fdexception;
+ FD_ZERO(&fdexception);
+ FD_SET((SOCKET)socketDescriptor, &fdexception);
+
+ ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
+
+ // ... but if it is actually set, pretend it did not happen
+ if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
+ ret--;
+ }
+
+ if (readEnabled)
+ readNotifier->setEnabled(true);
+
+ return ret;
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(int timeout,
+ bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const
+{
+ bool readEnabled = checkRead && readNotifier && readNotifier->isEnabled();
+ if (readEnabled)
+ readNotifier->setEnabled(false);
+
+ fd_set fdread;
+ fd_set fdwrite;
+ fd_set fdexception;
+
+ int ret = 0;
+
+ memset(&fdread, 0, sizeof(fd_set));
+ if (checkRead) {
+ fdread.fd_count = 1;
+ fdread.fd_array[0] = (SOCKET)socketDescriptor;
+ }
+ memset(&fdwrite, 0, sizeof(fd_set));
+ FD_ZERO(&fdexception);
+ if (checkWrite) {
+ fdwrite.fd_count = 1;
+ fdwrite.fd_array[0] = (SOCKET)socketDescriptor;
+
+ // Windows needs this to report errors when connecting a socket
+ FD_SET((SOCKET)socketDescriptor, &fdexception);
+ }
+
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+#if !defined(Q_OS_WINCE)
+ ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
+#else
+ ret = select(1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
+#endif
+
+ //... but if it is actually set, pretend it did not happen
+ if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
+ ret--;
+
+ if (readEnabled)
+ readNotifier->setEnabled(true);
+
+ if (ret <= 0)
+ return ret;
+
+ *selectForRead = FD_ISSET((SOCKET)socketDescriptor, &fdread);
+ *selectForWrite = FD_ISSET((SOCKET)socketDescriptor, &fdwrite);
+
+ return ret;
+}
+
+void QNativeSocketEnginePrivate::nativeClose()
+{
+#if defined (QTCPSOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeClose()");
+#endif
+ // We were doing a setsockopt here before with SO_DONTLINGER. (However with kind of wrong
+ // usage of parameters, it wants a BOOL but we used a struct and pretended it to be bool).
+ // We don't think setting this option should be done here, if a user wants it she/he can
+ // do it manually with socketDescriptor()/setSocketDescriptor();
+ ::closesocket(socketDescriptor);
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
new file mode 100644
index 0000000000..c406ed948c
--- /dev/null
+++ b/src/network/socket/qnet_unix_p.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNET_UNIX_P_H
+#define QNET_UNIX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of Qt code on Unix. This header file may change from version to
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qcore_unix_p.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#if defined(Q_OS_VXWORKS)
+# include <sockLib.h>
+#endif
+
+// for inet_addr
+#include <netdb.h>
+#include <arpa/inet.h>
+#if defined(Q_OS_VXWORKS)
+# include <hostLib.h>
+#else
+# include <resolv.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// Almost always the same. If not, specify in qplatformdefs.h.
+#if !defined(QT_SOCKOPTLEN_T)
+# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
+#endif
+
+// UnixWare 7 redefines socket -> _socket
+static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
+{
+ Q_ASSERT((flags & ~O_NONBLOCK) == 0);
+
+ register int fd;
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ int newtype = type | SOCK_CLOEXEC;
+ if (flags & O_NONBLOCK)
+ newtype |= SOCK_NONBLOCK;
+ fd = ::socket(domain, newtype, protocol);
+ if (fd != -1 || errno != EINVAL)
+ return fd;
+#endif
+
+ fd = ::socket(domain, type, protocol);
+ if (fd == -1)
+ return -1;
+
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ // set non-block too?
+ if (flags & O_NONBLOCK)
+ ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ return fd;
+}
+
+// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
+static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags = 0)
+{
+ Q_ASSERT((flags & ~O_NONBLOCK) == 0);
+
+ register int fd;
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ // use accept4
+ int sockflags = SOCK_CLOEXEC;
+ if (flags & O_NONBLOCK)
+ sockflags |= SOCK_NONBLOCK;
+ fd = ::accept4(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), sockflags);
+ if (fd != -1 || !(errno == ENOSYS || errno == EINVAL))
+ return fd;
+#endif
+
+ fd = ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen));
+ if (fd == -1)
+ return -1;
+
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ // set non-block too?
+ if (flags & O_NONBLOCK)
+ ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ return fd;
+}
+
+// UnixWare 7 redefines listen -> _listen
+static inline int qt_safe_listen(int s, int backlog)
+{
+ return ::listen(s, backlog);
+}
+
+static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen)
+{
+ register int ret;
+ // Solaris e.g. expects a non-const 2nd parameter
+ EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
+ return ret;
+}
+#undef QT_SOCKET_CONNECT
+#define QT_SOCKET_CONNECT qt_safe_connect
+
+#if defined(socket)
+# undef socket
+#endif
+#if defined(accept)
+# undef accept
+#endif
+#if defined(listen)
+# undef listen
+#endif
+
+// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
+template <typename T>
+static inline int qt_safe_ioctl(int sockfd, int request, T arg)
+{
+#ifdef Q_OS_VXWORKS
+ return ::ioctl(sockfd, request, (int) arg);
+#else
+ return ::ioctl(sockfd, request, arg);
+#endif
+}
+
+// VxWorks' headers do not specify any const modifiers
+static inline in_addr_t qt_safe_inet_addr(const char *cp)
+{
+#ifdef Q_OS_VXWORKS
+ return ::inet_addr((char *) cp);
+#else
+ return ::inet_addr(cp);
+#endif
+}
+
+// VxWorks' headers do not specify any const modifiers
+static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *to, QT_SOCKLEN_T tolen)
+{
+#ifdef MSG_NOSIGNAL
+ flags |= MSG_NOSIGNAL;
+#endif
+
+ register int ret;
+#ifdef Q_OS_VXWORKS
+ EINTR_LOOP(ret, ::sendto(sockfd, (char *) buf, len, flags, (struct sockaddr *) to, tolen));
+#else
+ EINTR_LOOP(ret, ::sendto(sockfd, buf, len, flags, to, tolen));
+#endif
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#endif // QNET_UNIX_P_H
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
new file mode 100644
index 0000000000..c365635990
--- /dev/null
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -0,0 +1,1923 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsocks5socketengine_p.h"
+
+#ifndef QT_NO_SOCKS5
+
+#include "qtcpsocket.h"
+#include "qudpsocket.h"
+#include "qtcpserver.h"
+#include "qdebug.h"
+#include "qhash.h"
+#include "qqueue.h"
+#include "qelapsedtimer.h"
+#include "qmutex.h"
+#include "qthread.h"
+#include "qcoreapplication.h"
+#include "qurl.h"
+#include "qauthenticator.h"
+#include <qendian.h>
+#include <qnetworkinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_SYMBIAN
+static const int MaxWriteBufferSize = 4*1024;
+#else
+static const int MaxWriteBufferSize = 128*1024;
+#endif
+
+//#define QSOCKS5SOCKETLAYER_DEBUG
+
+#define MAX_DATA_DUMP 256
+#if !defined(Q_OS_WINCE)
+#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
+#else
+#define SOCKS5_BLOCKING_BIND_TIMEOUT 10000
+#endif
+
+#define Q_INIT_CHECK(returnValue) do { \
+ if (!d->data) { \
+ return returnValue; \
+ } } while (0)
+
+#define S5_VERSION_5 0x05
+#define S5_CONNECT 0x01
+#define S5_BIND 0x02
+#define S5_UDP_ASSOCIATE 0x03
+#define S5_IP_V4 0x01
+#define S5_DOMAINNAME 0x03
+#define S5_IP_V6 0x04
+#define S5_SUCCESS 0x00
+#define S5_R_ERROR_SOCKS_FAILURE 0x01
+#define S5_R_ERROR_CON_NOT_ALLOWED 0x02
+#define S5_R_ERROR_NET_UNREACH 0x03
+#define S5_R_ERROR_HOST_UNREACH 0x04
+#define S5_R_ERROR_CONN_REFUSED 0x05
+#define S5_R_ERROR_TTL 0x06
+#define S5_R_ERROR_CMD_NOT_SUPPORTED 0x07
+#define S5_R_ERROR_ADD_TYPE_NOT_SUPORTED 0x08
+
+#define S5_AUTHMETHOD_NONE 0x00
+#define S5_AUTHMETHOD_PASSWORD 0x02
+#define S5_AUTHMETHOD_NOTACCEPTABLE 0xFF
+
+#define S5_PASSWORDAUTH_VERSION 0x01
+
+#ifdef QSOCKS5SOCKETLAYER_DEBUG
+# define QSOCKS5_Q_DEBUG qDebug() << this
+# define QSOCKS5_D_DEBUG qDebug() << q_ptr
+# define QSOCKS5_DEBUG qDebug() << "[QSocks5]"
+static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s)
+{
+ switch (s) {
+ case QSocks5SocketEnginePrivate::Uninitialized: return QLatin1String("Uninitialized");
+ case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("ConnectError");
+ case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent");
+ case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating");
+ case QSocks5SocketEnginePrivate::AuthenticatingError: return QLatin1String("AuthenticatingError");
+ case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent");
+ case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError");
+ case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected");
+ case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return QLatin1String("UdpAssociateSuccess");
+ case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("BindSuccess");
+ case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError");
+ case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError");
+ case QSocks5SocketEnginePrivate::HostNameLookupError: return QLatin1String("HostNameLookupError");
+ default: break;
+ }
+ return QLatin1String("unknown state");
+}
+
+static QString dump(const QByteArray &buf)
+{
+ QString data;
+ for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) {
+ if (i) data += QLatin1Char(' ');
+ uint val = (unsigned char)buf.at(i);
+ // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0'));
+ data += QString::number(val);
+ }
+ if (buf.size() > MAX_DATA_DUMP)
+ data += QLatin1String(" ...");
+
+ return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);
+}
+
+#else
+# define QSOCKS5_DEBUG if (0) qDebug()
+# define QSOCKS5_Q_DEBUG if (0) qDebug()
+# define QSOCKS5_D_DEBUG if (0) qDebug()
+
+static inline QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State) { return QString(); }
+static inline QString dump(const QByteArray &) { return QString(); }
+#endif
+
+/*
+ inserts the host address in buf at pos and updates pos.
+ if the func fails the data in buf and the vallue of pos is undefined
+*/
+static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
+{
+ QSOCKS5_DEBUG << "setting [" << address << ':' << port << ']';
+
+ union {
+ quint16 port;
+ quint32 ipv4;
+ QIPv6Address ipv6;
+ char ptr;
+ } data;
+
+ // add address
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ data.ipv4 = qToBigEndian<quint32>(address.toIPv4Address());
+ pBuf->append(S5_IP_V4);
+ pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv4));
+ } else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ data.ipv6 = address.toIPv6Address();
+ pBuf->append(S5_IP_V6);
+ pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv6));
+ } else {
+ return false;
+ }
+
+ // add port
+ data.port = qToBigEndian<quint16>(port);
+ pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
+ return true;
+}
+
+/*
+ like above, but for a hostname
+*/
+static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
+{
+ QSOCKS5_DEBUG << "setting [" << hostname << ':' << port << ']';
+
+ QByteArray encodedHostName = QUrl::toAce(hostname);
+ QByteArray &buf = *pBuf;
+
+ if (encodedHostName.length() > 255)
+ return false;
+
+ buf.append(S5_DOMAINNAME);
+ buf.append(uchar(encodedHostName.length()));
+ buf.append(encodedHostName);
+
+ // add port
+ union {
+ quint16 port;
+ char ptr;
+ } data;
+ data.port = qToBigEndian<quint16>(port);
+ buf.append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
+
+ return true;
+}
+
+
+/*
+ retrives the host address in buf at pos and updates pos.
+ if the func fails the value of the address and the pos is undefined
+*/
+static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos)
+{
+ bool ret = false;
+ int pos = *pPos;
+ const unsigned char *pBuf = reinterpret_cast<const unsigned char*>(buf.constData());
+ QHostAddress address;
+ quint16 port = 0;
+
+ if (buf.size() - pos < 1) {
+ QSOCKS5_DEBUG << "need more data address/port";
+ return false;
+ }
+ if (pBuf[pos] == S5_IP_V4) {
+ pos++;
+ if (buf.size() - pos < 4) {
+ QSOCKS5_DEBUG << "need more data for ip4 address";
+ return false;
+ }
+ address.setAddress(qFromBigEndian<quint32>(&pBuf[pos]));
+ pos += 4;
+ ret = true;
+ } else if (pBuf[pos] == S5_IP_V6) {
+ pos++;
+ if (buf.size() - pos < 16) {
+ QSOCKS5_DEBUG << "need more data for ip6 address";
+ return false;
+ }
+ QIPv6Address add;
+ for (int i = 0; i < 16; ++i)
+ add[i] = buf[pos++];
+ ret = true;
+ } else if (pBuf[pos] == S5_DOMAINNAME){
+ // just skip it
+ pos++;
+ qDebug() << "skipping hostname of len" << uint(pBuf[pos]);
+ pos += uchar(pBuf[pos]);
+ } else {
+ QSOCKS5_DEBUG << "invalid address type" << (int)pBuf[pos];
+ ret = false;
+ }
+
+ if (ret) {
+ if (buf.size() - pos < 2) {
+ QSOCKS5_DEBUG << "need more data for port";
+ return false;
+ }
+ port = qFromBigEndian<quint16>(&pBuf[pos]);
+ pos += 2;
+ }
+
+ if (ret) {
+ QSOCKS5_DEBUG << "got [" << address << ':' << port << ']';
+ *pAddress = address;
+ *pPort = port;
+ *pPos = pos;
+ }
+
+ return ret;
+}
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+struct QSocks5Data
+{
+ QTcpSocket *controlSocket;
+ QSocks5Authenticator *authenticator;
+};
+
+struct QSocks5ConnectData : public QSocks5Data
+{
+ QByteArray readBuffer;
+};
+
+struct QSocks5BindData : public QSocks5Data
+{
+ QHostAddress localAddress;
+ quint16 localPort;
+ QHostAddress peerAddress;
+ quint16 peerPort;
+ QElapsedTimer timeStamp;
+};
+
+struct QSocks5RevivedDatagram
+{
+ QByteArray data;
+ QHostAddress address;
+ quint16 port;
+};
+
+#ifndef QT_NO_UDPSOCKET
+struct QSocks5UdpAssociateData : public QSocks5Data
+{
+ QUdpSocket *udpSocket;
+ QHostAddress associateAddress;
+ quint16 associatePort;
+ QQueue<QSocks5RevivedDatagram> pendingDatagrams;
+};
+#endif
+
+// needs to be thread safe
+class QSocks5BindStore : public QObject
+{
+public:
+ QSocks5BindStore();
+ ~QSocks5BindStore();
+
+ void add(int socketDescriptor, QSocks5BindData *bindData);
+ bool contains(int socketDescriptor);
+ QSocks5BindData *retrieve(int socketDescriptor);
+
+protected:
+ void timerEvent(QTimerEvent * event);
+
+ QMutex mutex;
+ int sweepTimerId;
+ //socket descriptor, data, timestamp
+ QHash<int, QSocks5BindData *> store;
+};
+
+Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
+
+QSocks5BindStore::QSocks5BindStore()
+ : mutex(QMutex::Recursive)
+ , sweepTimerId(-1)
+{
+ QCoreApplication *app = QCoreApplication::instance();
+ if (app && app->thread() != thread())
+ moveToThread(app->thread());
+}
+
+QSocks5BindStore::~QSocks5BindStore()
+{
+}
+
+void QSocks5BindStore::add(int socketDescriptor, QSocks5BindData *bindData)
+{
+ QMutexLocker lock(&mutex);
+ if (store.contains(socketDescriptor)) {
+ // qDebug() << "delete it";
+ }
+ bindData->timeStamp.start();
+ store.insert(socketDescriptor, bindData);
+ // start sweep timer if not started
+ if (sweepTimerId == -1)
+ sweepTimerId = startTimer(60000);
+}
+
+bool QSocks5BindStore::contains(int socketDescriptor)
+{
+ QMutexLocker lock(&mutex);
+ return store.contains(socketDescriptor);
+}
+
+QSocks5BindData *QSocks5BindStore::retrieve(int socketDescriptor)
+{
+ QMutexLocker lock(&mutex);
+ if (!store.contains(socketDescriptor))
+ return 0;
+ QSocks5BindData *bindData = store.take(socketDescriptor);
+ if (bindData) {
+ if (bindData->controlSocket->thread() != QThread::currentThread()) {
+ qWarning("Can not access socks5 bind data from different thread");
+ return 0;
+ }
+ } else {
+ QSOCKS5_DEBUG << "__ERROR__ binddata == 0";
+ }
+ // stop the sweep timer if not needed
+ if (store.isEmpty()) {
+ killTimer(sweepTimerId);
+ sweepTimerId = -1;
+ }
+ return bindData;
+}
+
+void QSocks5BindStore::timerEvent(QTimerEvent * event)
+{
+ QMutexLocker lock(&mutex);
+ if (event->timerId() == sweepTimerId) {
+ QSOCKS5_DEBUG << "QSocks5BindStore performing sweep";
+ QMutableHashIterator<int, QSocks5BindData *> it(store);
+ while (it.hasNext()) {
+ it.next();
+ if (it.value()->timeStamp.hasExpired(350000)) {
+ QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ";
+ it.remove();
+ }
+ }
+ }
+}
+
+QSocks5Authenticator::QSocks5Authenticator()
+{
+}
+
+QSocks5Authenticator::~QSocks5Authenticator()
+{
+}
+
+char QSocks5Authenticator::methodId()
+{
+ return 0x00;
+}
+
+bool QSocks5Authenticator::beginAuthenticate(QTcpSocket *socket, bool *completed)
+{
+ Q_UNUSED(socket);
+ *completed = true;
+ return true;
+}
+
+bool QSocks5Authenticator::continueAuthenticate(QTcpSocket *socket, bool *completed)
+{
+ Q_UNUSED(socket);
+ *completed = true;
+ return true;
+}
+
+bool QSocks5Authenticator::seal(const QByteArray buf, QByteArray *sealedBuf)
+{
+ *sealedBuf = buf;
+ return true;
+}
+
+bool QSocks5Authenticator::unSeal(const QByteArray sealedBuf, QByteArray *buf)
+{
+ *buf = sealedBuf;
+ return true;
+}
+
+bool QSocks5Authenticator::unSeal(QTcpSocket *sealedSocket, QByteArray *buf)
+{
+ return unSeal(sealedSocket->readAll(), buf);
+}
+
+QSocks5PasswordAuthenticator::QSocks5PasswordAuthenticator(const QString &userName, const QString &password)
+{
+ this->userName = userName;
+ this->password = password;
+}
+
+char QSocks5PasswordAuthenticator::methodId()
+{
+ return 0x02;
+}
+
+bool QSocks5PasswordAuthenticator::beginAuthenticate(QTcpSocket *socket, bool *completed)
+{
+ *completed = false;
+ QByteArray uname = userName.toLatin1();
+ QByteArray passwd = password.toLatin1();
+ QByteArray dataBuf(3 + uname.size() + passwd.size(), 0);
+ char *buf = dataBuf.data();
+ int pos = 0;
+ buf[pos++] = S5_PASSWORDAUTH_VERSION;
+ buf[pos++] = uname.size();
+ memcpy(&buf[pos], uname.data(), uname.size());
+ pos += uname.size();
+ buf[pos++] = passwd.size();
+ memcpy(&buf[pos], passwd.data(), passwd.size());
+ return socket->write(dataBuf) == dataBuf.size();
+}
+
+bool QSocks5PasswordAuthenticator::continueAuthenticate(QTcpSocket *socket, bool *completed)
+{
+ *completed = false;
+
+ if (socket->bytesAvailable() < 2)
+ return true;
+
+ QByteArray buf = socket->read(2);
+ if (buf.at(0) == S5_PASSWORDAUTH_VERSION && buf.at(1) == 0x00) {
+ *completed = true;
+ return true;
+ }
+
+ // must disconnect
+ socket->close();
+ return false;
+}
+
+QString QSocks5PasswordAuthenticator::errorString()
+{
+ return QLatin1String("Socks5 user name or password incorrect");
+}
+
+
+
+QSocks5SocketEnginePrivate::QSocks5SocketEnginePrivate()
+ : socks5State(Uninitialized)
+ , readNotificationEnabled(false)
+ , writeNotificationEnabled(false)
+ , exceptNotificationEnabled(false)
+ , socketDescriptor(-1)
+ , data(0)
+ , connectData(0)
+#ifndef QT_NO_UDPSOCKET
+ , udpData(0)
+#endif
+ , bindData(0)
+ , readNotificationActivated(false)
+ , writeNotificationActivated(false)
+ , readNotificationPending(false)
+ , writeNotificationPending(false)
+ , connectionNotificationPending(false)
+{
+ mode = NoMode;
+}
+
+QSocks5SocketEnginePrivate::~QSocks5SocketEnginePrivate()
+{
+}
+
+void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode)
+{
+ Q_Q(QSocks5SocketEngine);
+
+ mode = socks5Mode;
+ if (mode == ConnectMode) {
+ connectData = new QSocks5ConnectData;
+ data = connectData;
+#ifndef QT_NO_UDPSOCKET
+ } else if (mode == UdpAssociateMode) {
+ udpData = new QSocks5UdpAssociateData;
+ data = udpData;
+ udpData->udpSocket = new QUdpSocket(q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
+ udpData->udpSocket->setProxy(QNetworkProxy::NoProxy);
+ QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
+ q, SLOT(_q_udpSocketReadNotification()),
+ Qt::DirectConnection);
+#endif // QT_NO_UDPSOCKET
+ } else if (mode == BindMode) {
+ bindData = new QSocks5BindData;
+ data = bindData;
+ }
+
+ data->controlSocket = new QTcpSocket(q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
+ data->controlSocket->setProxy(QNetworkProxy::NoProxy);
+ QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()),
+ Qt::DirectConnection);
+ QObject::connect(data->controlSocket, SIGNAL(readyRead()), q, SLOT(_q_controlSocketReadNotification()),
+ Qt::DirectConnection);
+ QObject::connect(data->controlSocket, SIGNAL(bytesWritten(qint64)), q, SLOT(_q_controlSocketBytesWritten()),
+ Qt::DirectConnection);
+ QObject::connect(data->controlSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ q, SLOT(_q_controlSocketError(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+ QObject::connect(data->controlSocket, SIGNAL(disconnected()), q, SLOT(_q_controlSocketDisconnected()),
+ Qt::DirectConnection);
+ QObject::connect(data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ q, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
+ Qt::DirectConnection);
+
+ if (!proxyInfo.user().isEmpty() || !proxyInfo.password().isEmpty()) {
+ QSOCKS5_D_DEBUG << "using username/password authentication; user =" << proxyInfo.user();
+ data->authenticator = new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
+ } else {
+ QSOCKS5_D_DEBUG << "not using authentication";
+ data->authenticator = new QSocks5Authenticator();
+ }
+}
+
+void QSocks5SocketEnginePrivate::setErrorState(Socks5State state, const QString &extraMessage)
+{
+ Q_Q(QSocks5SocketEngine);
+
+ switch (state) {
+ case Uninitialized:
+ case Authenticating:
+ case AuthenticationMethodsSent:
+ case RequestMethodSent:
+ case Connected:
+ case UdpAssociateSuccess:
+ case BindSuccess:
+ // these aren't error states
+ return;
+
+ case ConnectError:
+ case ControlSocketError: {
+ QAbstractSocket::SocketError controlSocketError = data->controlSocket->error();
+ if (socks5State != Connected) {
+ switch (controlSocketError) {
+ case QAbstractSocket::ConnectionRefusedError:
+ q->setError(QAbstractSocket::ProxyConnectionRefusedError,
+ QSocks5SocketEngine::tr("Connection to proxy refused"));
+ break;
+ case QAbstractSocket::RemoteHostClosedError:
+ q->setError(QAbstractSocket::ProxyConnectionClosedError,
+ QSocks5SocketEngine::tr("Connection to proxy closed prematurely"));
+ break;
+ case QAbstractSocket::HostNotFoundError:
+ q->setError(QAbstractSocket::ProxyNotFoundError,
+ QSocks5SocketEngine::tr("Proxy host not found"));
+ break;
+ case QAbstractSocket::SocketTimeoutError:
+ if (state == ConnectError) {
+ q->setError(QAbstractSocket::ProxyConnectionTimeoutError,
+ QSocks5SocketEngine::tr("Connection to proxy timed out"));
+ break;
+ }
+ /* fall through */
+ default:
+ q->setError(controlSocketError, data->controlSocket->errorString());
+ break;
+ }
+ } else {
+ q->setError(controlSocketError, data->controlSocket->errorString());
+ }
+ break;
+ }
+
+ case AuthenticatingError:
+ q->setError(QAbstractSocket::ProxyAuthenticationRequiredError,
+ extraMessage.isEmpty() ?
+ QSocks5SocketEngine::tr("Proxy authentication failed") :
+ QSocks5SocketEngine::tr("Proxy authentication failed: %1").arg(extraMessage));
+ break;
+
+ case RequestError:
+ // error code set by caller (overload)
+ break;
+
+ case SocksError:
+ q->setError(QAbstractSocket::ProxyProtocolError,
+ QSocks5SocketEngine::tr("SOCKS version 5 protocol error"));
+ break;
+
+ case HostNameLookupError:
+ q->setError(QAbstractSocket::HostNotFoundError,
+ QAbstractSocket::tr("Host not found"));
+ break;
+ }
+
+ q->setState(QAbstractSocket::UnconnectedState);
+ socks5State = state;
+}
+
+void QSocks5SocketEnginePrivate::setErrorState(Socks5State state, Socks5Error socks5error)
+{
+ Q_Q(QSocks5SocketEngine);
+ switch (socks5error) {
+ case SocksFailure:
+ q->setError(QAbstractSocket::NetworkError,
+ QSocks5SocketEngine::tr("General SOCKSv5 server failure"));
+ break;
+ case ConnectionNotAllowed:
+ q->setError(QAbstractSocket::SocketAccessError,
+ QSocks5SocketEngine::tr("Connection not allowed by SOCKSv5 server"));
+ break;
+ case NetworkUnreachable:
+ q->setError(QAbstractSocket::NetworkError,
+ QAbstractSocket::tr("Network unreachable"));
+ break;
+ case HostUnreachable:
+ q->setError(QAbstractSocket::HostNotFoundError,
+ QAbstractSocket::tr("Host not found"));
+ break;
+ case ConnectionRefused:
+ q->setError(QAbstractSocket::ConnectionRefusedError,
+ QAbstractSocket::tr("Connection refused"));
+ break;
+ case TTLExpired:
+ q->setError(QAbstractSocket::NetworkError,
+ QSocks5SocketEngine::tr("TTL expired"));
+ break;
+ case CommandNotSupported:
+ q->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSocks5SocketEngine::tr("SOCKSv5 command not supported"));
+ break;
+ case AddressTypeNotSupported:
+ q->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSocks5SocketEngine::tr("Address type not supported"));
+ break;
+
+ default:
+ q->setError(QAbstractSocket::UnknownSocketError,
+ QSocks5SocketEngine::tr("Unknown SOCKSv5 proxy error code 0x%1").arg(int(socks5error), 16));
+ break;
+ }
+
+ setErrorState(state, QString());
+}
+
+void QSocks5SocketEnginePrivate::reauthenticate()
+{
+ Q_Q(QSocks5SocketEngine);
+
+ // we require authentication
+ QAuthenticator auth;
+ emit q->proxyAuthenticationRequired(proxyInfo, &auth);
+
+ if (!auth.user().isEmpty() || !auth.password().isEmpty()) {
+ // we have new credentials, let's try again
+ QSOCKS5_DEBUG << "authentication failure: retrying connection";
+ socks5State = QSocks5SocketEnginePrivate::Uninitialized;
+
+ delete data->authenticator;
+ proxyInfo.setUser(auth.user());
+ proxyInfo.setPassword(auth.password());
+ data->authenticator = new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
+
+ data->controlSocket->blockSignals(true);
+ data->controlSocket->abort();
+ data->controlSocket->blockSignals(false);
+ data->controlSocket->connectToHost(proxyInfo.hostName(), proxyInfo.port());
+ } else {
+ // authentication failure
+
+ setErrorState(AuthenticatingError);
+ data->controlSocket->close();
+ emitConnectionNotification();
+ }
+}
+
+void QSocks5SocketEnginePrivate::parseAuthenticationMethodReply()
+{
+ // not enough data to begin
+ if (data->controlSocket->bytesAvailable() < 2)
+ return;
+
+ QByteArray buf = data->controlSocket->read(2);
+ if (buf.at(0) != S5_VERSION_5) {
+ QSOCKS5_D_DEBUG << "Socks5 version incorrect";
+ setErrorState(SocksError);
+ data->controlSocket->close();
+ emitConnectionNotification();
+ return;
+ }
+
+ bool authComplete = false;
+ if (uchar(buf.at(1)) == S5_AUTHMETHOD_NONE) {
+ authComplete = true;
+ } else if (uchar(buf.at(1)) == S5_AUTHMETHOD_NOTACCEPTABLE) {
+ reauthenticate();
+ return;
+ } else if (buf.at(1) != data->authenticator->methodId()
+ || !data->authenticator->beginAuthenticate(data->controlSocket, &authComplete)) {
+ setErrorState(AuthenticatingError, QLatin1String("Socks5 host did not support authentication method."));
+ socketError = QAbstractSocket::SocketAccessError; // change the socket error
+ emitConnectionNotification();
+ return;
+ }
+
+ if (authComplete)
+ sendRequestMethod();
+ else
+ socks5State = Authenticating;
+}
+
+void QSocks5SocketEnginePrivate::parseAuthenticatingReply()
+{
+ bool authComplete = false;
+ if (!data->authenticator->continueAuthenticate(data->controlSocket, &authComplete)) {
+ reauthenticate();
+ return;
+ }
+ if (authComplete)
+ sendRequestMethod();
+}
+
+void QSocks5SocketEnginePrivate::sendRequestMethod()
+{
+ QHostAddress address;
+ quint16 port = 0;
+ char command = 0;
+ if (mode == ConnectMode) {
+ command = S5_CONNECT;
+ address = peerAddress;
+ port = peerPort;
+ } else if (mode == BindMode) {
+ command = S5_BIND;
+ address = localAddress;
+ port = localPort;
+ } else {
+#ifndef QT_NO_UDPSOCKET
+ command = S5_UDP_ASSOCIATE;
+ address = localAddress; //data->controlSocket->localAddress();
+ port = localPort;
+#endif
+ }
+
+ QByteArray buf;
+ buf.reserve(270); // big enough for domain name;
+ buf[0] = S5_VERSION_5;
+ buf[1] = command;
+ buf[2] = 0x00;
+ if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
+ QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
+ //### set error code ....
+ return;
+ } else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) {
+ QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
+ //### set error code ....
+ return;
+ }
+ QSOCKS5_DEBUG << "sending" << dump(buf);
+ QByteArray sealedBuf;
+ if (!data->authenticator->seal(buf, &sealedBuf)) {
+ // ### Handle this error.
+ }
+ data->controlSocket->write(sealedBuf);
+ data->controlSocket->flush();
+ socks5State = RequestMethodSent;
+}
+
+void QSocks5SocketEnginePrivate::parseRequestMethodReply()
+{
+ Q_Q(QSocks5SocketEngine);
+ QSOCKS5_DEBUG << "parseRequestMethodReply()";
+
+ QByteArray inBuf;
+ if (!data->authenticator->unSeal(data->controlSocket, &inBuf)) {
+ // ### check error and not just not enough data
+ QSOCKS5_DEBUG << "unSeal failed, needs more data";
+ return;
+ }
+ QSOCKS5_DEBUG << dump(inBuf);
+ if (inBuf.size() < 2) {
+ QSOCKS5_DEBUG << "need more data for request reply header .. put this data somewhere";
+ return;
+ }
+
+ QHostAddress address;
+ quint16 port = 0;
+
+ if (inBuf.at(0) != S5_VERSION_5 || inBuf.length() < 3 || inBuf.at(2) != 0x00) {
+ QSOCKS5_DEBUG << "socks protocol error";
+ setErrorState(SocksError);
+ } else if (inBuf.at(1) != S5_SUCCESS) {
+ Socks5Error socks5Error = Socks5Error(inBuf.at(1));
+ QSOCKS5_DEBUG << "Request error :" << socks5Error;
+ if ((socks5Error == SocksFailure || socks5Error == ConnectionNotAllowed)
+ && !peerName.isEmpty()) {
+ // Dante seems to use this error code to indicate hostname resolution failure
+ setErrorState(HostNameLookupError);
+ } else {
+ setErrorState(RequestError, socks5Error);
+ }
+ } else {
+ // connection success, retrieve the remote addresses
+ int pos = 3;
+ if (!qt_socks5_get_host_address_and_port(inBuf, &address, &port, &pos)) {
+ QSOCKS5_DEBUG << "error getting address";
+ setErrorState(SocksError);
+ } else {
+ inBuf.remove(0, pos);
+ for (int i = inBuf.size() - 1; i >= 0 ; --i)
+ data->controlSocket->ungetChar(inBuf.at(i));
+ }
+ }
+
+ if (socks5State == RequestMethodSent) {
+ // no error
+ localAddress = address;
+ localPort = port;
+
+ if (mode == ConnectMode) {
+ socks5State = Connected;
+ // notify the upper layer that we're done
+ q->setState(QAbstractSocket::ConnectedState);
+ emitConnectionNotification();
+ } else if (mode == BindMode) {
+ socks5State = BindSuccess;
+ q->setState(QAbstractSocket::ListeningState);
+ } else {
+ socks5State = UdpAssociateSuccess;
+ }
+ } else if (socks5State == BindSuccess) {
+ // no error and we got a connection
+ bindData->peerAddress = address;
+ bindData->peerPort = port;
+
+ emitReadNotification();
+ } else {
+ // got an error
+ data->controlSocket->close();
+ emitConnectionNotification();
+ }
+}
+
+void QSocks5SocketEnginePrivate::_q_emitPendingReadNotification()
+{
+ Q_Q(QSocks5SocketEngine);
+ readNotificationPending = false;
+ if (readNotificationEnabled) {
+ QSOCKS5_D_DEBUG << "emitting readNotification";
+ QPointer<QSocks5SocketEngine> qq = q;
+ emit q->readNotification();
+ if (!qq)
+ return;
+ // check if there needs to be a new zero read notification
+ if (data && data->controlSocket->state() == QAbstractSocket::UnconnectedState
+ && data->controlSocket->error() == QAbstractSocket::RemoteHostClosedError) {
+ connectData->readBuffer.clear();
+ emitReadNotification();
+ }
+ }
+}
+
+void QSocks5SocketEnginePrivate::emitReadNotification()
+{
+ Q_Q(QSocks5SocketEngine);
+ readNotificationActivated = true;
+ if (readNotificationEnabled && !readNotificationPending) {
+ QSOCKS5_D_DEBUG << "queueing readNotification";
+ readNotificationPending = true;
+ QMetaObject::invokeMethod(q, "_q_emitPendingReadNotification", Qt::QueuedConnection);
+ }
+}
+
+void QSocks5SocketEnginePrivate::_q_emitPendingWriteNotification()
+{
+ writeNotificationPending = false;
+ Q_Q(QSocks5SocketEngine);
+ if (writeNotificationEnabled) {
+ QSOCKS5_D_DEBUG << "emitting writeNotification";
+ emit q->writeNotification();
+ }
+}
+
+void QSocks5SocketEnginePrivate::emitWriteNotification()
+{
+ Q_Q(QSocks5SocketEngine);
+ writeNotificationActivated = true;
+ if (writeNotificationEnabled && !writeNotificationPending) {
+ QSOCKS5_D_DEBUG << "queueing writeNotification";
+ writeNotificationPending = true;
+ QMetaObject::invokeMethod(q, "_q_emitPendingWriteNotification", Qt::QueuedConnection);
+ }
+}
+
+void QSocks5SocketEnginePrivate::_q_emitPendingConnectionNotification()
+{
+ connectionNotificationPending = false;
+ Q_Q(QSocks5SocketEngine);
+ QSOCKS5_D_DEBUG << "emitting connectionNotification";
+ emit q->connectionNotification();
+}
+
+void QSocks5SocketEnginePrivate::emitConnectionNotification()
+{
+ Q_Q(QSocks5SocketEngine);
+ QSOCKS5_D_DEBUG << "queueing connectionNotification";
+ connectionNotificationPending = true;
+ QMetaObject::invokeMethod(q, "_q_emitPendingConnectionNotification", Qt::QueuedConnection);
+}
+
+QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
+:QAbstractSocketEngine(*new QSocks5SocketEnginePrivate(), parent)
+{
+}
+
+QSocks5SocketEngine::~QSocks5SocketEngine()
+{
+ Q_D(QSocks5SocketEngine);
+
+ if (d->data) {
+ delete d->data->authenticator;
+ delete d->data->controlSocket;
+ }
+ if (d->connectData)
+ delete d->connectData;
+#ifndef QT_NO_UDPSOCKET
+ if (d->udpData) {
+ delete d->udpData->udpSocket;
+ delete d->udpData;
+ }
+#endif
+ if (d->bindData)
+ delete d->bindData;
+}
+
+static QBasicAtomicInt descriptorCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QSocks5SocketEngine);
+
+ d->socketDescriptor = descriptorCounter.fetchAndAddRelaxed(1);
+
+ d->socketType = type;
+ d->socketProtocol = protocol;
+
+ return true;
+}
+
+bool QSocks5SocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState)
+{
+ Q_D(QSocks5SocketEngine);
+
+ QSOCKS5_Q_DEBUG << "initialize" << socketDescriptor;
+
+ // this is only valid for the other side of a bind, nothing else is supported
+
+ if (socketState != QAbstractSocket::ConnectedState) {
+ //### must be connected state ???
+ return false;
+ }
+
+ QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
+ if (bindData) {
+
+ d->socketState = QAbstractSocket::ConnectedState;
+ d->socketType = QAbstractSocket::TcpSocket;
+ d->connectData = new QSocks5ConnectData;
+ d->data = d->connectData;
+ d->mode = QSocks5SocketEnginePrivate::ConnectMode;
+ d->data->controlSocket = bindData->controlSocket;
+ bindData->controlSocket = 0;
+ d->data->controlSocket->setParent(this);
+ d->socketProtocol = d->data->controlSocket->localAddress().protocol();
+ d->data->authenticator = bindData->authenticator;
+ bindData->authenticator = 0;
+ d->localPort = bindData->localPort;
+ d->localAddress = bindData->localAddress;
+ d->peerPort = bindData->peerPort;
+ d->peerAddress = bindData->peerAddress;
+ delete bindData;
+
+ QObject::connect(d->data->controlSocket, SIGNAL(connected()), this, SLOT(_q_controlSocketConnected()),
+ Qt::DirectConnection);
+ QObject::connect(d->data->controlSocket, SIGNAL(readyRead()), this, SLOT(_q_controlSocketReadNotification()),
+ Qt::DirectConnection);
+ QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_controlSocketBytesWritten()),
+ Qt::DirectConnection);
+ QObject::connect(d->data->controlSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_controlSocketError(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+ QObject::connect(d->data->controlSocket, SIGNAL(disconnected()), this, SLOT(_q_controlSocketDisconnected()),
+ Qt::DirectConnection);
+ QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
+ Qt::DirectConnection);
+
+ d->socks5State = QSocks5SocketEnginePrivate::Connected;
+
+ if (d->data->controlSocket->bytesAvailable() != 0)
+ d->_q_controlSocketReadNotification();
+ return true;
+ }
+ return false;
+}
+
+void QSocks5SocketEngine::setProxy(const QNetworkProxy &networkProxy)
+{
+ Q_D(QSocks5SocketEngine);
+ d->proxyInfo = networkProxy;
+}
+
+int QSocks5SocketEngine::socketDescriptor() const
+{
+ Q_D(const QSocks5SocketEngine);
+ return d->socketDescriptor;
+}
+
+bool QSocks5SocketEngine::isValid() const
+{
+ Q_D(const QSocks5SocketEngine);
+ return d->socketType != QAbstractSocket::UnknownSocketType
+ && d->socks5State != QSocks5SocketEnginePrivate::SocksError
+ && (d->socketError == QAbstractSocket::UnknownSocketError
+ || d->socketError == QAbstractSocket::SocketTimeoutError
+ || d->socketError == QAbstractSocket::UnfinishedSocketOperationError);
+}
+
+bool QSocks5SocketEngine::connectInternal()
+{
+ Q_D(QSocks5SocketEngine);
+
+ if (!d->data) {
+ if (socketType() == QAbstractSocket::TcpSocket) {
+ d->initialize(QSocks5SocketEnginePrivate::ConnectMode);
+#ifndef QT_NO_UDPSOCKET
+ } else if (socketType() == QAbstractSocket::UdpSocket) {
+ d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
+ // all udp needs to be bound
+ if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0))
+ return false;
+
+ setState(QAbstractSocket::ConnectedState);
+ return true;
+#endif
+ } else {
+ qFatal("QSocks5SocketEngine::connectToHost: in QTcpServer mode");
+ return false;
+ }
+ }
+
+ if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
+ && d->socketState != QAbstractSocket::ConnectingState) {
+ setState(QAbstractSocket::ConnectingState);
+ d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
+ return false;
+ }
+ return false;
+}
+
+bool QSocks5SocketEngine::connectToHost(const QHostAddress &address, quint16 port)
+{
+ Q_D(QSocks5SocketEngine);
+ QSOCKS5_DEBUG << "connectToHost" << address << ':' << port;
+
+ setPeerAddress(address);
+ setPeerPort(port);
+ d->peerName.clear();
+
+ return connectInternal();
+}
+
+bool QSocks5SocketEngine::connectToHostByName(const QString &hostname, quint16 port)
+{
+ Q_D(QSocks5SocketEngine);
+
+ setPeerAddress(QHostAddress());
+ setPeerPort(port);
+ d->peerName = hostname;
+
+ return connectInternal();
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketConnected()
+{
+ QSOCKS5_DEBUG << "_q_controlSocketConnected";
+ QByteArray buf(3, 0);
+ buf[0] = S5_VERSION_5;
+ buf[1] = 0x01;
+ buf[2] = data->authenticator->methodId();
+ data->controlSocket->write(buf);
+ socks5State = AuthenticationMethodsSent;
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification()
+{
+ QSOCKS5_D_DEBUG << "_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
+ << "bytes available" << data->controlSocket->bytesAvailable();
+
+ if (data->controlSocket->bytesAvailable() == 0) {
+ QSOCKS5_D_DEBUG << "########## bogus read why do we get these ... on windows only";
+ return;
+ }
+
+ switch (socks5State) {
+ case AuthenticationMethodsSent:
+ parseAuthenticationMethodReply();
+ break;
+ case Authenticating:
+ parseAuthenticatingReply();
+ break;
+ case RequestMethodSent:
+ parseRequestMethodReply();
+ break;
+ case Connected: {
+ QByteArray buf;
+ if (!data->authenticator->unSeal(data->controlSocket, &buf)) {
+ // qDebug() << "unseal error maybe need to wait for more data";
+ }
+ if (buf.size()) {
+ QSOCKS5_DEBUG << dump(buf);
+ connectData->readBuffer += buf;
+ emitReadNotification();
+ }
+ break;
+ }
+ case BindSuccess:
+ // only get here if command is bind
+ if (mode == BindMode) {
+ parseRequestMethodReply();
+ break;
+ }
+
+ // fall through
+ default:
+ qWarning("QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
+ "Unexpectedly received data while in state=%d and mode=%d",
+ socks5State, mode);
+ break;
+ };
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketBytesWritten()
+{
+ QSOCKS5_DEBUG << "_q_controlSocketBytesWritten";
+
+ if (socks5State != Connected
+ || (mode == ConnectMode
+ && data->controlSocket->bytesToWrite()))
+ return;
+ if (data->controlSocket->bytesToWrite() < MaxWriteBufferSize) {
+ emitWriteNotification();
+ writeNotificationActivated = false;
+ }
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketError(QAbstractSocket::SocketError error)
+{
+ QSOCKS5_D_DEBUG << "controlSocketError" << error << data->controlSocket->errorString();
+
+ if (error == QAbstractSocket::SocketTimeoutError)
+ return; // ignore this error -- comes from the waitFor* functions
+
+ if (error == QAbstractSocket::RemoteHostClosedError
+ && socks5State == Connected) {
+ // clear the read buffer in connect mode so that bytes available returns 0
+ // if there already is a read notification pending then this will be processed first
+ if (!readNotificationPending)
+ connectData->readBuffer.clear();
+ emitReadNotification();
+ data->controlSocket->close();
+ // cause a disconnect in the outer socket
+ emitWriteNotification();
+ } else if (socks5State == Uninitialized
+ || socks5State == AuthenticationMethodsSent
+ || socks5State == Authenticating
+ || socks5State == RequestMethodSent) {
+ setErrorState(socks5State == Uninitialized ? ConnectError : ControlSocketError);
+ data->controlSocket->close();
+ emitConnectionNotification();
+ } else {
+ q_func()->setError(data->controlSocket->error(), data->controlSocket->errorString());
+ emitReadNotification();
+ emitWriteNotification();
+ }
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketDisconnected()
+{
+ QSOCKS5_D_DEBUG << "_q_controlSocketDisconnected";
+}
+
+void QSocks5SocketEnginePrivate::_q_controlSocketStateChanged(QAbstractSocket::SocketState state)
+{
+ QSOCKS5_D_DEBUG << "_q_controlSocketStateChanged" << state;
+}
+
+#ifndef QT_NO_UDPSOCKET
+void QSocks5SocketEnginePrivate::checkForDatagrams() const
+{
+ // udp should be unbuffered so we need to do some polling at certain points
+ if (udpData->udpSocket->hasPendingDatagrams())
+ const_cast<QSocks5SocketEnginePrivate *>(this)->_q_udpSocketReadNotification();
+}
+
+void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification()
+{
+ QSOCKS5_D_DEBUG << "_q_udpSocketReadNotification()";
+
+ // check some state stuff
+ if (!udpData->udpSocket->hasPendingDatagrams()) {
+ QSOCKS5_D_DEBUG << "false read ??";
+ return;
+ }
+
+ while (udpData->udpSocket->hasPendingDatagrams()) {
+ QByteArray sealedBuf(udpData->udpSocket->pendingDatagramSize(), 0);
+ QSOCKS5_D_DEBUG << "new datagram";
+ udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
+ QByteArray inBuf;
+ if (!data->authenticator->unSeal(sealedBuf, &inBuf)) {
+ QSOCKS5_D_DEBUG << "failed unsealing datagram discarding";
+ return;
+ }
+ QSOCKS5_DEBUG << dump(inBuf);
+ int pos = 0;
+ const char *buf = inBuf.constData();
+ if (inBuf.size() < 4) {
+ QSOCKS5_D_DEBUG << "bugus udp data, discarding";
+ return;
+ }
+ QSocks5RevivedDatagram datagram;
+ if (buf[pos++] != 0 || buf[pos++] != 0) {
+ QSOCKS5_D_DEBUG << "invalid datagram discarding";
+ return;
+ }
+ if (buf[pos++] != 0) { //### add fragmentation reading support
+ QSOCKS5_D_DEBUG << "don't support fragmentation yet disgarding";
+ return;
+ }
+ if (!qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos)) {
+ QSOCKS5_D_DEBUG << "failed to get address from datagram disgarding";
+ return;
+ }
+ datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
+ udpData->pendingDatagrams.enqueue(datagram);
+ }
+ emitReadNotification();
+}
+#endif // QT_NO_UDPSOCKET
+
+bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QSocks5SocketEngine);
+
+ // when bind wee will block until the bind is finished as the info from the proxy server is needed
+
+ if (!d->data) {
+ if (socketType() == QAbstractSocket::TcpSocket) {
+ d->initialize(QSocks5SocketEnginePrivate::BindMode);
+#ifndef QT_NO_UDPSOCKET
+ } else if (socketType() == QAbstractSocket::UdpSocket) {
+ d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
+#endif
+ } else {
+ //### something invalid
+ return false;
+ }
+ }
+
+#ifndef QT_NO_UDPSOCKET
+ if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
+ if (!d->udpData->udpSocket->bind(address, port)) {
+ QSOCKS5_Q_DEBUG << "local udp bind failed";
+ setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
+ return false;
+ }
+ d->localAddress = d->udpData->udpSocket->localAddress();
+ d->localPort = d->udpData->udpSocket->localPort();
+ } else
+#endif
+ if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
+ d->localAddress = address;
+ d->localPort = port;
+ } else {
+ //### something invalid
+ return false;
+ }
+
+ int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+ d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
+ if (!d->waitForConnected(msecs, 0) ||
+ d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
+ // waitForConnected sets the error state and closes the socket
+ QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
+ return false;
+ }
+ if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
+ setState(QAbstractSocket::BoundState);
+ return true;
+#ifndef QT_NO_UDPSOCKET
+ } else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
+ setState(QAbstractSocket::BoundState);
+ d->udpData->associateAddress = d->localAddress;
+ d->localAddress = QHostAddress();
+ d->udpData->associatePort = d->localPort;
+ d->localPort = 0;
+ QUdpSocket dummy;
+#ifndef QT_NO_BEARERMANAGEMENT
+ dummy.setProperty("_q_networksession", property("_q_networksession"));
+#endif
+ dummy.setProxy(QNetworkProxy::NoProxy);
+ if (!dummy.bind()
+ || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
+ || !dummy.waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))
+ || dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) {
+ QSOCKS5_DEBUG << "udp actual address and port lookup failed";
+ setState(QAbstractSocket::UnconnectedState);
+ setError(dummy.error(), dummy.errorString());
+ d->data->controlSocket->close();
+ //### reset and error
+ return false;
+ }
+ QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ':' << d->localPort;
+ return true;
+#endif // QT_NO_UDPSOCKET
+ }
+
+ // binding timed out
+ setError(QAbstractSocket::SocketTimeoutError,
+ QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
+
+///### delete d->udpSocket;
+///### d->udpSocket = 0;
+ return false;
+}
+
+
+bool QSocks5SocketEngine::listen()
+{
+ Q_D(QSocks5SocketEngine);
+
+ QSOCKS5_Q_DEBUG << "listen()";
+
+ // check that we are in bound and then go to listening.
+ if (d->socketState == QAbstractSocket::BoundState) {
+ d->socketState = QAbstractSocket::ListeningState;
+
+ // check if we already have a connection
+ if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
+ d->emitReadNotification();
+
+ return true;
+ }
+ return false;
+}
+
+int QSocks5SocketEngine::accept()
+{
+ Q_D(QSocks5SocketEngine);
+ // check we are listing ---
+
+ QSOCKS5_Q_DEBUG << "accept()";
+
+ if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
+ QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store";
+ d->data->controlSocket->disconnect();
+ d->data->controlSocket->setParent(0);
+ d->bindData->localAddress = d->localAddress;
+ d->bindData->localPort = d->localPort;
+ int sd = d->socketDescriptor;
+ socks5BindStore()->add(sd, d->bindData);
+ d->data = 0;
+ d->bindData = 0;
+ d->socketDescriptor = 0;
+ //### do something about this socket layer ... set it closed and an error about why ...
+ // reset state and local port/address
+ d->socks5State = QSocks5SocketEnginePrivate::Uninitialized; // ..??
+ d->socketState = QAbstractSocket::UnconnectedState;
+ return sd;
+ }
+ return -1;
+}
+
+void QSocks5SocketEngine::close()
+{
+ QSOCKS5_Q_DEBUG << "close()";
+ Q_D(QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
+ int msecs = 100;
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+ while (!d->data->controlSocket->bytesToWrite()) {
+ if (!d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed())))
+ break;
+ }
+ }
+ d->data->controlSocket->close();
+ }
+#ifndef QT_NO_UDPSOCKET
+ if (d->udpData && d->udpData->udpSocket)
+ d->udpData->udpSocket->close();
+#endif
+}
+
+qint64 QSocks5SocketEngine::bytesAvailable() const
+{
+ Q_D(const QSocks5SocketEngine);
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
+ return d->connectData->readBuffer.size();
+#ifndef QT_NO_UDPSOCKET
+ else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
+ && !d->udpData->pendingDatagrams.isEmpty())
+ return d->udpData->pendingDatagrams.first().data.size();
+#endif
+ return 0;
+}
+
+qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
+{
+ Q_D(QSocks5SocketEngine);
+ QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
+ if (d->connectData->readBuffer.size() == 0) {
+ if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
+ //imitate remote closed
+ close();
+ setError(QAbstractSocket::RemoteHostClosedError,
+ QLatin1String("Remote host closed connection###"));
+ setState(QAbstractSocket::UnconnectedState);
+ return -1;
+ } else {
+ return 0; // nothing to be read
+ }
+ }
+ qint64 copy = qMin<qint64>(d->connectData->readBuffer.size(), maxlen);
+ memcpy(data, d->connectData->readBuffer.constData(), copy);
+ d->connectData->readBuffer.remove(0, copy);
+ QSOCKS5_DEBUG << "read" << dump(QByteArray(data, copy));
+ return copy;
+#ifndef QT_NO_UDPSOCKET
+ } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
+ return readDatagram(data, maxlen);
+#endif
+ }
+ return 0;
+}
+
+qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
+{
+ Q_D(QSocks5SocketEngine);
+ QSOCKS5_Q_DEBUG << "write" << dump(QByteArray(data, len));
+
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
+ // clamp down the amount of bytes to transfer at once
+ len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
+ if (len <= 0)
+ return 0;
+
+ QByteArray buf = QByteArray::fromRawData(data, len);
+ QByteArray sealedBuf;
+ if (!d->data->authenticator->seal(buf, &sealedBuf)) {
+ // ### Handle this error.
+ }
+
+ d->data->controlSocket->write(sealedBuf);
+ d->data->controlSocket->waitForBytesWritten(0);
+ return len;
+#ifndef QT_NO_UDPSOCKET
+ } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
+ // send to connected address
+ return writeDatagram(data, len, d->peerAddress, d->peerPort);
+#endif
+ }
+ //### set an error ???
+ return -1;
+}
+
+#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+bool QSocks5SocketEngine::joinMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+
+QNetworkInterface QSocks5SocketEngine::multicastInterface() const
+{
+ return QNetworkInterface();
+}
+
+bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+#endif // QT_NO_NETWORKINTERFACE
+
+qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr,
+ quint16 *port)
+{
+ Q_D(QSocks5SocketEngine);
+
+ d->checkForDatagrams();
+
+ if (d->udpData->pendingDatagrams.isEmpty())
+ return 0;
+
+ QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
+ int copyLen = qMin<int>(maxlen, datagram.data.size());
+ memcpy(data, datagram.data.constData(), copyLen);
+ if (addr)
+ *addr = datagram.address;
+ if (port)
+ *port = datagram.port;
+ return copyLen;
+}
+
+qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &address,
+ quint16 port)
+{
+ Q_D(QSocks5SocketEngine);
+
+ // it is possible to send with out first binding with udp, but socks5 requires a bind.
+ if (!d->data) {
+ d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
+ // all udp needs to be bound
+ if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
+ //### set error
+ return -1;
+ }
+ }
+
+ QByteArray outBuf;
+ outBuf.reserve(270 + len);
+ outBuf[0] = 0x00;
+ outBuf[1] = 0x00;
+ outBuf[2] = 0x00;
+ if (!qt_socks5_set_host_address_and_port(address, port, &outBuf)) {
+ }
+ outBuf += QByteArray(data, len);
+ QSOCKS5_DEBUG << "sending" << dump(outBuf);
+ QByteArray sealedBuf;
+ if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
+ QSOCKS5_DEBUG << "sealing data failed";
+ setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
+ return -1;
+ }
+ if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
+ //### try frgamenting
+ if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
+ setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
+ //### else maybe more serious error
+ return -1;
+ }
+
+ return len;
+}
+
+bool QSocks5SocketEngine::hasPendingDatagrams() const
+{
+ Q_D(const QSocks5SocketEngine);
+ Q_INIT_CHECK(false);
+
+ d->checkForDatagrams();
+
+ return !d->udpData->pendingDatagrams.isEmpty();
+}
+
+qint64 QSocks5SocketEngine::pendingDatagramSize() const
+{
+ Q_D(const QSocks5SocketEngine);
+
+ d->checkForDatagrams();
+
+ if (!d->udpData->pendingDatagrams.isEmpty())
+ return d->udpData->pendingDatagrams.head().data.size();
+ return 0;
+}
+#endif // QT_NO_UDPSOCKET
+
+qint64 QSocks5SocketEngine::bytesToWrite() const
+{
+ Q_D(const QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ return d->data->controlSocket->bytesToWrite();
+ } else {
+ return 0;
+ }
+}
+
+int QSocks5SocketEngine::option(SocketOption option) const
+{
+ Q_D(const QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
+ }
+ return -1;
+}
+
+bool QSocks5SocketEngine::setOption(SocketOption option, int value)
+{
+ Q_D(QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
+ return true;
+ }
+ return false;
+}
+
+bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
+{
+ if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
+ return false;
+
+ const Socks5State wantedState =
+ mode == ConnectMode ? Connected :
+ mode == BindMode ? BindSuccess :
+ UdpAssociateSuccess;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ while (socks5State != wantedState) {
+ if (!data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
+ return true;
+
+ setErrorState(QSocks5SocketEnginePrivate::ControlSocketError);
+ if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(QSocks5SocketEngine);
+ QSOCKS5_DEBUG << "waitForRead" << msecs;
+
+ d->readNotificationActivated = false;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // are we connected yet?
+ if (!d->waitForConnected(msecs, timedOut))
+ return false;
+ if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
+ return true;
+
+ // we're connected
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
+ d->mode == QSocks5SocketEnginePrivate::BindMode) {
+ while (!d->readNotificationActivated) {
+ if (!d->data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
+ return true;
+
+ setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
+ if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ return false;
+ }
+ }
+#ifndef QT_NO_UDPSOCKET
+ } else {
+ while (!d->readNotificationActivated) {
+ if (!d->udpData->udpSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
+ if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
+ *timedOut = true;
+ return false;
+ }
+ }
+#endif // QT_NO_UDPSOCKET
+ }
+
+
+ bool ret = d->readNotificationActivated;
+ d->readNotificationActivated = false;
+
+ QSOCKS5_DEBUG << "waitForRead returned" << ret;
+ return ret;
+}
+
+
+bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_D(QSocks5SocketEngine);
+ QSOCKS5_DEBUG << "waitForWrite" << msecs;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ // are we connected yet?
+ if (!d->waitForConnected(msecs, timedOut))
+ return false;
+ if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
+ return true;
+
+ // we're connected
+
+ // flush any bytes we may still have buffered in the time that we have left
+ if (d->data->controlSocket->bytesToWrite())
+ d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
+ while ((msecs == -1 || stopWatch.elapsed() < msecs)
+ && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
+ && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
+ d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
+ return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
+}
+
+bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_UNUSED(checkRead);
+ if (!checkWrite) {
+ bool canRead = waitForRead(msecs, timedOut);
+ if (readyToRead)
+ *readyToRead = canRead;
+ return canRead;
+ }
+
+ bool canWrite = waitForWrite(msecs, timedOut);
+ if (readyToWrite)
+ *readyToWrite = canWrite;
+ return canWrite;
+}
+
+bool QSocks5SocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QSocks5SocketEngine);
+ return d->readNotificationEnabled;
+}
+
+void QSocks5SocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QSocks5SocketEngine);
+
+ QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')';
+
+ bool emitSignal = false;
+ if (!d->readNotificationEnabled
+ && enable) {
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
+ emitSignal = !d->connectData->readBuffer.isEmpty();
+#ifndef QT_NO_UDPSOCKET
+ else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
+ emitSignal = !d->udpData->pendingDatagrams.isEmpty();
+#endif
+ else if (d->mode == QSocks5SocketEnginePrivate::BindMode
+ && d->socketState == QAbstractSocket::ListeningState
+ && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
+ emitSignal = true;
+ }
+
+ d->readNotificationEnabled = enable;
+
+ if (emitSignal)
+ d->emitReadNotification();
+}
+
+bool QSocks5SocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QSocks5SocketEngine);
+ return d->writeNotificationEnabled;
+}
+
+void QSocks5SocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QSocks5SocketEngine);
+ d->writeNotificationEnabled = enable;
+ if (enable && d->socketState == QAbstractSocket::ConnectedState) {
+ if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
+ return; // will be emitted as a result of bytes written
+ d->emitWriteNotification();
+ d->writeNotificationActivated = false;
+ }
+}
+
+bool QSocks5SocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QSocks5SocketEngine);
+ return d->exceptNotificationEnabled;
+}
+
+void QSocks5SocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QSocks5SocketEngine);
+ d->exceptNotificationEnabled = enable;
+}
+
+QAbstractSocketEngine *
+QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
+ const QNetworkProxy &proxy, QObject *parent)
+{
+ Q_UNUSED(socketType);
+
+ // proxy type must have been resolved by now
+ if (proxy.type() != QNetworkProxy::Socks5Proxy) {
+ QSOCKS5_DEBUG << "not proxying";
+ return 0;
+ }
+ QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
+ engine->setProxy(proxy);
+ return engine.take();
+}
+
+QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(int socketDescriptor, QObject *parent)
+{
+ QSOCKS5_DEBUG << "createSocketEngine" << socketDescriptor;
+ if (socks5BindStore()->contains(socketDescriptor)) {
+ QSOCKS5_DEBUG << "bind store contains" << socketDescriptor;
+ return new QSocks5SocketEngine(parent);
+ }
+ return 0;
+}
+
+#endif // QT_NO_SOCKS5
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
new file mode 100644
index 0000000000..9492d4532d
--- /dev/null
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -0,0 +1,299 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSOCKS5SOCKETENGINE_P_H
+#define QSOCKS5SOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qabstractsocketengine_p.h"
+#include "qnetworkproxy.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SOCKS5
+
+class QSocks5SocketEnginePrivate;
+
+class Q_AUTOTEST_EXPORT QSocks5SocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+public:
+ QSocks5SocketEngine(QObject *parent = 0);
+ ~QSocks5SocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ void setProxy(const QNetworkProxy &networkProxy);
+
+ int socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectInternal();
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+ qint64 bytesAvailable() const;
+
+ qint64 read(char *data, qint64 maxlen);
+ qint64 write(const char *data, qint64 len);
+
+#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif // QT_NO_NETWORKINTERFACE
+
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+#endif // QT_NO_UDPSOCKET
+
+ qint64 bytesToWrite() const;
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+private:
+ Q_DECLARE_PRIVATE(QSocks5SocketEngine)
+ Q_DISABLE_COPY(QSocks5SocketEngine)
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketConnected())
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketReadNotification())
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketError(QAbstractSocket::SocketError))
+#ifndef QT_NO_UDPSOCKET
+ Q_PRIVATE_SLOT(d_func(), void _q_udpSocketReadNotification())
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketBytesWritten())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitPendingReadNotification())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitPendingWriteNotification())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitPendingConnectionNotification())
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketDisconnected())
+ Q_PRIVATE_SLOT(d_func(), void _q_controlSocketStateChanged(QAbstractSocket::SocketState))
+
+};
+
+
+class QTcpSocket;
+
+class QSocks5Authenticator
+{
+public:
+ QSocks5Authenticator();
+ virtual ~QSocks5Authenticator();
+ virtual char methodId();
+ virtual bool beginAuthenticate(QTcpSocket *socket, bool *completed);
+ virtual bool continueAuthenticate(QTcpSocket *socket, bool *completed);
+
+ virtual bool seal(const QByteArray buf, QByteArray *sealedBuf);
+ virtual bool unSeal(const QByteArray sealedBuf, QByteArray *buf);
+ virtual bool unSeal(QTcpSocket *sealedSocket, QByteArray *buf);
+
+ virtual QString errorString() { return QString(); }
+};
+
+class QSocks5PasswordAuthenticator : public QSocks5Authenticator
+{
+public:
+ QSocks5PasswordAuthenticator(const QString &userName, const QString &password);
+ char methodId();
+ bool beginAuthenticate(QTcpSocket *socket, bool *completed);
+ bool continueAuthenticate(QTcpSocket *socket, bool *completed);
+
+ QString errorString();
+
+private:
+ QString userName;
+ QString password;
+};
+
+struct QSocks5Data;
+struct QSocks5ConnectData;
+struct QSocks5UdpAssociateData;
+struct QSocks5BindData;
+
+class QSocks5SocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QSocks5SocketEngine)
+public:
+ QSocks5SocketEnginePrivate();
+ ~QSocks5SocketEnginePrivate();
+
+ enum Socks5State
+ {
+ Uninitialized = 0,
+ ConnectError,
+ AuthenticationMethodsSent,
+ Authenticating,
+ AuthenticatingError,
+ RequestMethodSent,
+ RequestError,
+ Connected,
+ UdpAssociateSuccess,
+ BindSuccess,
+ ControlSocketError,
+ SocksError,
+ HostNameLookupError
+ };
+ Socks5State socks5State;
+
+ enum Socks5Mode
+ {
+ NoMode,
+ ConnectMode,
+ BindMode,
+ UdpAssociateMode
+ };
+ Socks5Mode mode;
+
+ enum Socks5Error
+ {
+ SocksFailure = 0x01,
+ ConnectionNotAllowed = 0x02,
+ NetworkUnreachable = 0x03,
+ HostUnreachable = 0x04,
+ ConnectionRefused = 0x05,
+ TTLExpired = 0x06,
+ CommandNotSupported = 0x07,
+ AddressTypeNotSupported = 0x08,
+ LastKnownError = AddressTypeNotSupported,
+ UnknownError
+ };
+
+ void initialize(Socks5Mode socks5Mode);
+
+ void setErrorState(Socks5State state, const QString &extraMessage = QString());
+ void setErrorState(Socks5State state, Socks5Error socks5error);
+
+ void reauthenticate();
+ void parseAuthenticationMethodReply();
+ void parseAuthenticatingReply();
+ void sendRequestMethod();
+ void parseRequestMethodReply();
+ void parseNewConnection();
+
+ bool waitForConnected(int msecs, bool *timedOut);
+
+ void _q_controlSocketConnected();
+ void _q_controlSocketReadNotification();
+ void _q_controlSocketError(QAbstractSocket::SocketError);
+#ifndef QT_NO_UDPSOCKET
+ void checkForDatagrams() const;
+ void _q_udpSocketReadNotification();
+#endif
+ void _q_controlSocketBytesWritten();
+ void _q_controlSocketDisconnected();
+ void _q_controlSocketStateChanged(QAbstractSocket::SocketState);
+
+ QNetworkProxy proxyInfo;
+
+ bool readNotificationEnabled, writeNotificationEnabled, exceptNotificationEnabled;
+
+ int socketDescriptor;
+
+ QSocks5Data *data;
+ QSocks5ConnectData *connectData;
+#ifndef QT_NO_UDPSOCKET
+ QSocks5UdpAssociateData *udpData;
+#endif
+ QSocks5BindData *bindData;
+ QString peerName;
+
+ mutable bool readNotificationActivated;
+ mutable bool writeNotificationActivated;
+
+ bool readNotificationPending;
+ void _q_emitPendingReadNotification();
+ void emitReadNotification();
+ bool writeNotificationPending;
+ void _q_emitPendingWriteNotification();
+ void emitWriteNotification();
+ bool connectionNotificationPending;
+ void _q_emitPendingConnectionNotification();
+ void emitConnectionNotification();
+};
+
+class Q_AUTOTEST_EXPORT QSocks5SocketEngineHandler : public QSocketEngineHandler
+{
+public:
+ virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType,
+ const QNetworkProxy &, QObject *parent);
+ virtual QAbstractSocketEngine *createSocketEngine(int socketDescripter, QObject *parent);
+};
+
+
+QT_END_NAMESPACE
+#endif // QT_NO_SOCKS5
+#endif // QSOCKS5SOCKETENGINE_H
diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp
new file mode 100644
index 0000000000..f1b2982626
--- /dev/null
+++ b/src/network/socket/qsymbiansocketengine.cpp
@@ -0,0 +1,1730 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+#include "qsymbiansocketengine_p.h"
+
+#include "qiodevice.h"
+#include "qhostaddress.h"
+#include "qelapsedtimer.h"
+#include "qvarlengtharray.h"
+#include "qnetworkinterface.h"
+#include <private/qnetworksession_p.h>
+#include <es_sock.h>
+#include <in_sock.h>
+#include <net/if.h>
+
+#include <private/qcore_symbian_p.h>
+
+#if !defined(QT_NO_NETWORKPROXY)
+# include "qnetworkproxy.h"
+# include "qabstractsocket.h"
+# include "qtcpserver.h"
+#endif
+
+#include <QCoreApplication>
+
+#include <qabstracteventdispatcher.h>
+#include <private/qeventdispatcher_symbian_p.h>
+#include <qsocketnotifier.h>
+#include <qnetworkinterface.h>
+
+#include <private/qthread_p.h>
+#include <private/qobject_p.h>
+#include <private/qsystemerror_p.h>
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+#include <qstring.h>
+#include <ctype.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define Q_VOID
+// Common constructs
+#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
+ if (!isValid()) { \
+ qWarning(""#function" was called on an uninitialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
+ if (isValid()) { \
+ qWarning(""#function" was called on an already initialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_STATE(function, checkState, returnValue) do { \
+ if (d->socketState != (checkState)) { \
+ qWarning(""#function" was not called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
+ if (d->socketState == (checkState)) { \
+ qWarning(""#function" was called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
+ if (d->socketState != (state1) && d->socketState != (state2)) { \
+ qWarning(""#function" was called" \
+ " not in "#state1" or "#state2); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_TYPE(function, type, returnValue) do { \
+ if (d->socketType != (type)) { \
+ qWarning(#function" was called by a" \
+ " socket other than "#type""); \
+ return (returnValue); \
+ } } while (0)
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+
+/*
+ Returns a human readable representation of the first \a len
+ characters in \a data.
+*/
+static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
+{
+ if (!data) return "(null)";
+ QByteArray out;
+ for (int i = 0; i < len; ++i) {
+ char c = data[i];
+ if (isprint(c)) {
+ out += c;
+ } else switch (c) {
+ case '\n': out += "\\n"; break;
+ case '\r': out += "\\r"; break;
+ case '\t': out += "\\t"; break;
+ default:
+ QString tmp;
+ tmp.sprintf("\\%o", c);
+ out += tmp.toLatin1();
+ }
+ }
+
+ if (len < maxSize)
+ out += "...";
+
+ return out;
+}
+#endif
+
+void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr)
+{
+ if (a.Family() == KAfInet6 && !a.IsV4Compat() && !a.IsV4Mapped()) {
+ Q_IPV6ADDR tmp;
+ memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp));
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(tmp);
+ *addr = tmpAddress;
+ TPckgBuf<TSoInetIfQuery> query;
+ query().iSrcAddr = a;
+ TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query);
+ if (!err)
+ addr->setScopeId(qt_TDesC2QString(query().iName));
+ else
+ addr->setScopeId(QString::number(a.Scope()));
+ }
+ if (port)
+ *port = a.Port();
+ return;
+ }
+ if (port)
+ *port = a.Port();
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(a.Address());
+ *addr = tmpAddress;
+ }
+}
+/*! \internal
+
+ Creates and returns a new socket descriptor of type \a socketType
+ and \a socketProtocol. Returns -1 on failure.
+*/
+bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
+ QAbstractSocket::NetworkLayerProtocol socketProtocol)
+{
+ Q_Q(QSymbianSocketEngine);
+ TUint family = KAfInet; // KAfInet6 is only used as an address family, not as a protocol family
+ TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream;
+ TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp;
+
+ //Check if there is a user specified session
+ QVariant v(q->property("_q_networksession"));
+ TInt err;
+ if (v.isValid()) {
+ QSharedPointer<QNetworkSession> s = qvariant_cast<QSharedPointer<QNetworkSession> >(v);
+ err = QNetworkSessionPrivate::nativeOpenSocket(*s, nativeSocket, family, type, protocol);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << err;
+#endif
+ } else
+ err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead
+
+ if (err != KErrNone) {
+ switch (err) {
+ case KErrNotSupported:
+ case KErrNotFound:
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ ProtocolUnsupportedErrorString);
+ break;
+ default:
+ setError(err);
+ break;
+ }
+
+ return false;
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - created" << nativeSocket.SubSessionHandle();
+#endif
+ socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << " - allocated socket descriptor" << socketDescriptor;
+#endif
+ return true;
+}
+
+void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr)
+{
+ nativeAddr.SetPort(port);
+ if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
+ TPckgBuf<TSoInetIfQuery> query;
+ query().iName = qt_QString2TPtrC(addr.scopeId());
+ TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query);
+ if (!err)
+ nativeAddr.SetScope(query().iIndex);
+ else
+ nativeAddr.SetScope(0);
+ Q_IPV6ADDR ip6 = addr.toIPv6Address();
+ TIp6Addr v6addr;
+ memcpy(v6addr.u.iAddr8, ip6.c, 16);
+ nativeAddr.SetAddress(v6addr);
+ } else if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
+ nativeAddr.SetAddress(addr.toIPv4Address());
+ } else {
+ qWarning("unsupported network protocol (%d)", addr.protocol());
+ }
+}
+
+QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() :
+ socketDescriptor(-1),
+ socketServer(QSymbianSocketManager::instance().getSocketServer()),
+ readNotificationsEnabled(false),
+ writeNotificationsEnabled(false),
+ exceptNotificationsEnabled(false),
+ asyncSelect(0)
+{
+}
+
+QSymbianSocketEnginePrivate::~QSymbianSocketEnginePrivate()
+{
+}
+
+
+QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent)
+ : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent)
+{
+}
+
+
+QSymbianSocketEngine::~QSymbianSocketEngine()
+{
+ close();
+}
+
+/*!
+ Initializes a QSymbianSocketEngine by creating a new socket of type \a
+ socketType and network layer protocol \a protocol. Returns true on
+ success; otherwise returns false.
+
+ If the socket was already initialized, this function closes the
+ socket before reeinitializing it.
+
+ The new socket is non-blocking, and for UDP sockets it's also
+ broadcast enabled.
+*/
+bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QSymbianSocketEngine);
+ if (isValid())
+ close();
+
+ // Create the socket
+ if (!d->createNewSocket(socketType, protocol)) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString typeStr = QLatin1String("UnknownSocketType");
+ if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
+ else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
+ QString protocolStr = QLatin1String("UnknownProtocol");
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
+ qDebug("QSymbianSocketEngine::initialize(type == %s, protocol == %s) failed: %s",
+ typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+
+ // Make sure we receive out-of-band data
+ if (socketType == QAbstractSocket::TcpSocket
+ && !setOption(ReceiveOutOfBandData, 1)) {
+ qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data");
+ }
+
+
+ d->socketType = socketType;
+ d->socketProtocol = protocol;
+ return true;
+}
+
+/*! \overload
+
+ Initializes the socket using \a socketDescriptor instead of
+ creating a new one. The socket type and network layer protocol are
+ determined automatically. The socket's state is set to \a
+ socketState.
+
+ If the socket type is either TCP or UDP, it is made non-blocking.
+ UDP sockets are also broadcast enabled.
+ */
+bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState)
+{
+ Q_D(QSymbianSocketEngine);
+
+ if (isValid())
+ close();
+
+ if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) {
+ qWarning("QSymbianSocketEngine::initialize - socket descriptor not found");
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSymbianSocketEnginePrivate::InvalidSocketErrorString);
+ return false;
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::initialize - attached to" << d->nativeSocket.SubSessionHandle() << socketDescriptor;
+#endif
+ Q_ASSERT(d->socketDescriptor == socketDescriptor || d->socketDescriptor == -1);
+ d->socketDescriptor = socketDescriptor;
+
+ // determine socket type and protocol
+ if (!d->fetchConnectionParameters()) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::initialize(socketDescriptor == %i) failed: %s",
+ socketDescriptor, d->socketErrorString.toLatin1().constData());
+#endif
+ d->socketDescriptor = -1;
+ return false;
+ }
+
+ if (d->socketType != QAbstractSocket::UnknownSocketType) {
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (d->socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Make sure we receive out-of-band data
+ if (d->socketType == QAbstractSocket::TcpSocket
+ && !setOption(ReceiveOutOfBandData, 1)) {
+ qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data");
+ }
+ }
+
+ d->socketState = socketState;
+ return true;
+}
+
+/*!
+ Returns true if the socket is valid; otherwise returns false. A
+ socket is valid if it has not been successfully initialized, or if
+ it has been closed.
+*/
+bool QSymbianSocketEngine::isValid() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->socketDescriptor != -1;
+}
+
+
+/*!
+ Returns the native socket descriptor. Any use of this descriptor
+ stands the risk of being non-portable.
+*/
+int QSymbianSocketEngine::socketDescriptor() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->socketDescriptor;
+}
+
+/*
+ Sets the socket option \a opt to \a v.
+*/
+bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setOption(), false);
+
+ TUint n = 0;
+ TUint level = KSOLSocket; // default
+
+ if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level))
+ return false;
+
+ if (!level && !n)
+ return true;
+
+ return (KErrNone == d->nativeSocket.SetOpt(n, level, v));
+}
+
+/*
+ Returns the value of the socket option \a opt.
+*/
+int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::option(), -1);
+
+ TUint n;
+ TUint level = KSOLSocket; // default
+
+ if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level))
+ return false;
+
+ if (!level && !n)
+ return 1;
+
+ int v = -1;
+ //GetOpt() is non const
+ TInt err = d->nativeSocket.GetOpt(n, level, v);
+ if (!err)
+ return v;
+
+ return -1;
+}
+
+bool QSymbianSocketEnginePrivate::translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level)
+{
+
+ switch (opt) {
+ case QAbstractSocketEngine::ReceiveBufferSocketOption:
+ n = KSORecvBuf;
+ break;
+ case QAbstractSocketEngine::SendBufferSocketOption:
+ n = KSOSendBuf;
+ break;
+ case QAbstractSocketEngine::NonBlockingSocketOption:
+ n = KSONonBlockingIO;
+ break;
+ case QAbstractSocketEngine::AddressReusable:
+ level = KSolInetIp;
+ n = KSoReuseAddr;
+ break;
+ case QAbstractSocketEngine::BroadcastSocketOption:
+ case QAbstractSocketEngine::BindExclusively:
+ level = 0;
+ n = 0;
+ return true;
+ case QAbstractSocketEngine::ReceiveOutOfBandData:
+ level = KSolInetTcp;
+ n = KSoTcpOobInline;
+ break;
+ case QAbstractSocketEngine::LowDelayOption:
+ level = KSolInetTcp;
+ n = KSoTcpNoDelay;
+ break;
+ case QAbstractSocketEngine::KeepAliveOption:
+ level = KSolInetTcp;
+ n = KSoTcpKeepAlive;
+ break;
+ case QAbstractSocketEngine::MulticastLoopbackOption:
+ level = KSolInetIp;
+ n = KSoIp6MulticastLoop;
+ break;
+ case QAbstractSocketEngine::MulticastTtlOption:
+ level = KSolInetIp;
+ n = KSoIp6MulticastHops;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+qint64 QSymbianSocketEngine::receiveBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::receiveBufferSize(), -1);
+ return option(ReceiveBufferSocketOption);
+}
+
+void QSymbianSocketEngine::setReceiveBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReceiveBufferSize(), Q_VOID);
+ setOption(ReceiveBufferSocketOption, size);
+}
+
+qint64 QSymbianSocketEngine::sendBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), -1);
+ return option(SendBufferSocketOption);
+}
+
+void QSymbianSocketEngine::setSendBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), Q_VOID);
+ setOption(SendBufferSocketOption, size);
+}
+
+/*!
+ Connects to the remote host name given by \a name on port \a
+ port. When this function is called, the upper-level will not
+ perform a hostname lookup.
+
+ The native socket engine does not support this operation,
+ but some other socket engines (notably proxy-based ones) do.
+*/
+bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port)
+{
+ Q_UNUSED(name);
+ Q_UNUSED(port);
+ Q_D(QSymbianSocketEngine);
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSymbianSocketEnginePrivate::OperationUnsupportedErrorString);
+ return false;
+}
+
+/*!
+ If there's a connection activity on the socket, process it. Then
+ notify our parent if there really was activity.
+*/
+void QSymbianSocketEngine::connectionNotification()
+{
+ // FIXME check if we really need to do it like that in Symbian
+ Q_D(QSymbianSocketEngine);
+ Q_ASSERT(state() == QAbstractSocket::ConnectingState);
+
+ connectToHost(d->peerAddress, d->peerPort);
+ if (state() != QAbstractSocket::ConnectingState) {
+ // we changed states
+ QAbstractSocketEngine::connectionNotification();
+ }
+}
+
+
+bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::connectToHost(), false);
+
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor);
+#endif
+
+ if (!d->checkProxy(addr))
+ return false;
+
+ d->peerAddress = addr;
+ d->peerPort = port;
+
+ TInetAddr nativeAddr;
+ d->setPortAndAddress(nativeAddr, port, addr);
+ TRequestStatus status;
+ d->nativeSocket.Connect(nativeAddr, status);
+ User::WaitForRequest(status);
+ TInt err = status.Int();
+ //For non blocking connect, KErrAlreadyExists is returned from the second Connect() to indicate
+ //the connection is up. So treat this the same as KErrNone which would be returned from the first
+ //call if it wouldn't block. (e.g. winsock wrapper in the emulator ignores the nonblocking flag)
+ if (err && err != KErrAlreadyExists) {
+ switch (err) {
+ case KErrWouldBlock:
+ d->socketState = QAbstractSocket::ConnectingState;
+ break;
+ default:
+ d->setError(err);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+
+ if (d->socketState != QAbstractSocket::ConnectedState) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::connectToHost(%s, %i) == false (%s)",
+ addr.toString().toLatin1().constData(), port,
+ d->socketState == QAbstractSocket::ConnectingState
+ ? "Connection in progress" : d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::Connect(%s, %i) == true",
+ addr.toString().toLatin1().constData(), port);
+#endif
+
+ d->socketState = QAbstractSocket::ConnectedState;
+ d->fetchConnectionParameters();
+ return true;
+}
+
+bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bind(), false);
+
+ if (!d->checkProxy(address))
+ return false;
+
+ Q_CHECK_STATE(QSymbianSocketEngine::bind(), QAbstractSocket::UnconnectedState, false);
+
+ TInetAddr nativeAddr;
+ if (address == QHostAddress::Any || address == QHostAddress::AnyIPv6) {
+ //Should allow both IPv4 and IPv6
+ //Listening on "0.0.0.0" accepts ONLY ipv4 connections
+ //Listening on "::" accepts ONLY ipv6 connections
+ nativeAddr.SetFamily(KAFUnspec);
+ nativeAddr.SetPort(port);
+ } else {
+ d->setPortAndAddress(nativeAddr, port, address);
+ }
+
+ TInt err = d->nativeSocket.Bind(nativeAddr);
+#ifdef __WINS__
+ if (err == KErrArgument) // winsock prt returns wrong error code
+ err = KErrInUse;
+#endif
+
+ if (err) {
+ switch (err) {
+ case KErrNotFound:
+ // the specified interface was not found - use the error code expected
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError, QSymbianSocketEnginePrivate::AddressNotAvailableErrorString);
+ break;
+ default:
+ d->setError(err);
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bind(%s, %i) == false (%s)",
+ address.toString().toLatin1().constData(), port, d->socketErrorString.toLatin1().constData());
+#endif
+
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bind(%s, %i) == true",
+ address.toString().toLatin1().constData(), port);
+#endif
+ d->socketState = QAbstractSocket::BoundState;
+
+ d->fetchConnectionParameters();
+
+ // When we bind to unspecified address (to get a dual mode socket), report back the
+ // same type of address that was requested. This is required for SOCKS proxy to work.
+ if (nativeAddr.Family() == KAFUnspec)
+ d->localAddress = address;
+ return true;
+}
+
+bool QSymbianSocketEngine::listen()
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::listen(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::listen(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
+ TInt err = d->nativeSocket.Listen(50);
+ if (err) {
+ d->setError(err);
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::listen() == false (%s)",
+ d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::listen() == true");
+#endif
+
+ d->socketState = QAbstractSocket::ListeningState;
+ return true;
+}
+
+int QSymbianSocketEngine::accept()
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::accept(), -1);
+ Q_CHECK_STATE(QSymbianSocketEngine::accept(), QAbstractSocket::ListeningState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::accept(), QAbstractSocket::TcpSocket, false);
+ RSocket blankSocket;
+ blankSocket.Open(d->socketServer);
+ TRequestStatus status;
+ d->nativeSocket.Accept(blankSocket, status);
+ User::WaitForRequest(status);
+ if (status.Int()) {
+ blankSocket.Close();
+ if (status != KErrWouldBlock)
+ qWarning("QSymbianSocketEngine::accept() - error %d", status.Int());
+ return -1;
+ }
+
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::accept - created" << blankSocket.SubSessionHandle();
+#endif
+ int fd = QSymbianSocketManager::instance().addSocket(blankSocket);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << " - allocated socket descriptor" << fd;
+#endif
+ return fd;
+}
+
+qint64 QSymbianSocketEngine::bytesAvailable() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bytesAvailable(), -1);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false);
+ int nbytes = 0;
+ qint64 available = 0;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes);
+ if (err)
+ return 0;
+ available = (qint64) nbytes;
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bytesAvailable() == %lli", available);
+#endif
+ return available;
+}
+
+bool QSymbianSocketEngine::hasPendingDatagrams() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::hasPendingDatagrams(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
+ int nbytes;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes);
+ return err == KErrNone && nbytes > 0;
+}
+
+qint64 QSymbianSocketEngine::pendingDatagramSize() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::pendingDatagramSize(), false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
+ int nbytes;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes);
+ if (nbytes > 0) {
+ //nbytes includes IP header, which is of variable length (IPv4 with or without options, IPv6...)
+ QByteArray next(nbytes,0);
+ TPtr8 buffer((TUint8*)next.data(), next.size());
+ TInetAddr addr;
+ TRequestStatus status;
+ //TODO: rather than peek, should we save this for next call to readDatagram?
+ //what if calls don't match though?
+ d->nativeSocket.RecvFrom(buffer, addr, KSockReadPeek, status);
+ User::WaitForRequest(status);
+ if (status.Int())
+ return 0;
+ return buffer.Length();
+ }
+ return qint64(nbytes);
+}
+
+
+qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize,
+ QHostAddress *address, quint16 *port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::readDatagram(), -1);
+ Q_CHECK_TYPE(QSymbianSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false);
+ TPtr8 buffer((TUint8*)data, (int)maxSize);
+ TInetAddr addr;
+ TRequestStatus status;
+ d->nativeSocket.RecvFrom(buffer, addr, 0, status);
+ User::WaitForRequest(status); //Non blocking receive
+
+ if (status.Int()) {
+ d->setError(QAbstractSocket::NetworkError, d->ReceiveDatagramErrorString);
+ } else if (port || address) {
+ d->getPortAndAddress(addr, port, address);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ int len = buffer.Length();
+ qDebug("QSymbianSocketEngine::receiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
+ data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize,
+ address ? address->toString().toLatin1().constData() : "(nil)",
+ port ? *port : 0, (qint64) len);
+#endif
+
+ if (status.Int())
+ return -1;
+ return qint64(buffer.Length());
+}
+
+
+qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len,
+ const QHostAddress &host, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::writeDatagram(), -1);
+ Q_CHECK_TYPE(QSymbianSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
+ TPtrC8 buffer((TUint8*)data, (int)len);
+ TInetAddr addr;
+ d->setPortAndAddress(addr, port, host);
+ TSockXfrLength sentBytes;
+ TRequestStatus status;
+ d->nativeSocket.SendTo(buffer, addr, 0, status, sentBytes);
+ User::WaitForRequest(status); //Non blocking send
+ TInt err = status.Int();
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::writeDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli (err=%d)", data,
+ qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(),
+ port, (qint64) sentBytes(), err);
+#endif
+
+ if (err) {
+ switch (err) {
+ case KErrWouldBlock:
+ // do not error the socket. (otherwise socket layer is reset)
+ // On symbian^1 and earlier, KErrWouldBlock is returned when interface is not up yet
+ // On symbian^3, KErrNone is returned but sentBytes = 0
+ return 0;
+ case KErrTooBig:
+ d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString);
+ break;
+ default:
+ d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString);
+ }
+ return -1;
+ }
+
+ if (QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0) {
+ // This is evil hack, but for some reason native RSocket::SendTo returns 0,
+ // for large datagrams (such as 600 bytes). Based on comments from Open C team
+ // this should happen only in platforms <= S60 5.0.
+ return len;
+ }
+ return sentBytes();
+}
+
+// FIXME check where the native socket engine called that..
+bool QSymbianSocketEnginePrivate::fetchConnectionParameters()
+{
+ localPort = 0;
+ localAddress.clear();
+ peerPort = 0;
+ peerAddress.clear();
+
+ if (socketDescriptor == -1)
+ return false;
+
+ if (!nativeSocket.SubSessionHandle()) {
+ if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) {
+ setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
+ return false;
+ }
+ }
+
+ // Determine local address
+ TSockAddr addr;
+ nativeSocket.LocalName(addr);
+ getPortAndAddress(addr, &localPort, &localAddress);
+
+ // Determine protocol family
+ socketProtocol = localAddress.protocol();
+
+ // Determine the remote address
+ nativeSocket.RemoteName(addr);
+ getPortAndAddress(addr, &peerPort, &peerAddress);
+
+ // Determine the socket type (UDP/TCP)
+ TProtocolDesc protocol;
+ TInt err = nativeSocket.Info(protocol);
+ if (err) {
+ setError(err);
+ return false;
+ } else {
+ switch (protocol.iProtocol) {
+ case KProtocolInetTcp:
+ socketType = QAbstractSocket::TcpSocket;
+ break;
+ case KProtocolInetUdp:
+ socketType = QAbstractSocket::UdpSocket;
+ break;
+ default:
+ socketType = QAbstractSocket::UnknownSocketType;
+ break;
+ }
+ }
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString socketProtocolStr = QLatin1String("UnknownProtocol");
+ if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QLatin1String("IPv4Protocol");
+ else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QLatin1String("IPv6Protocol");
+
+ QString socketTypeStr = QLatin1String("UnknownSocketType");
+ if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QLatin1String("TcpSocket");
+ else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QLatin1String("UdpSocket");
+
+ qDebug("QSymbianSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
+ " peer == %s:%i, socket == %s - %s",
+ localAddress.toString().toLatin1().constData(), localPort,
+ peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
+ socketProtocolStr.toLatin1().constData());
+#endif
+ return true;
+}
+
+void QSymbianSocketEngine::close()
+{
+ if (!isValid())
+ return;
+ Q_D(QSymbianSocketEngine);
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::close()");
+#endif
+
+ d->readNotificationsEnabled = false;
+ d->writeNotificationsEnabled = false;
+ d->exceptNotificationsEnabled = false;
+ if (d->asyncSelect) {
+ d->asyncSelect->deleteLater();
+ d->asyncSelect = 0;
+ }
+
+ //TODO: call nativeSocket.Shutdown(EImmediate) in some cases?
+ if (d->socketType == QAbstractSocket::UdpSocket) {
+ //TODO: Close hangs without this, but only for UDP - why?
+ TRequestStatus stat;
+ d->nativeSocket.Shutdown(RSocket::EImmediate, stat);
+ User::WaitForRequest(stat);
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::close - closing socket" << d->nativeSocket.SubSessionHandle() << d->socketDescriptor;
+#endif
+ //remove must come before close to avoid a race where another thread gets the old subsession handle
+ //reused & asserts when calling QSymbianSocketManager::instance->addSocket
+ QSymbianSocketManager::instance().removeSocket(d->nativeSocket);
+ d->nativeSocket.Close();
+ d->socketDescriptor = -1;
+
+ d->socketState = QAbstractSocket::UnconnectedState;
+ d->hasSetSocketError = false;
+ d->localPort = 0;
+ d->localAddress.clear();
+ d->peerPort = 0;
+ d->peerAddress.clear();
+}
+
+qint64 QSymbianSocketEngine::write(const char *data, qint64 len)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::write(), -1);
+ Q_CHECK_STATE(QSymbianSocketEngine::write(), QAbstractSocket::ConnectedState, -1);
+ TPtrC8 buffer((TUint8*)data, (int)len);
+ TSockXfrLength sentBytes = 0;
+ TRequestStatus status;
+ d->nativeSocket.Send(buffer, 0, status, sentBytes);
+ User::WaitForRequest(status); //TODO: on emulator this blocks for write >16kB (non blocking IO not implemented properly?)
+ TInt err = status.Int();
+
+ if (err) {
+ switch (err) {
+ case KErrDisconnected:
+ case KErrEof:
+ sentBytes = -1;
+ d->setError(QAbstractSocket::RemoteHostClosedError, d->RemoteHostClosedErrorString);
+ close();
+ break;
+ case KErrTooBig:
+ d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString);
+ break;
+ case KErrWouldBlock:
+ break;
+ default:
+ sentBytes = -1;
+ d->setError(err);
+ close();
+ break;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::write(%p \"%s\", %llu) == %i",
+ data, qt_prettyDebug(data, qMin((int) len, 16),
+ (int) len).data(), len, (int) sentBytes());
+#endif
+
+ return qint64(sentBytes());
+}
+/*
+*/
+qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::read(), -1);
+ Q_CHECK_STATES(QSymbianSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);
+
+ TPtr8 buffer((TUint8*)data, (int)maxSize);
+ TSockXfrLength received = 0;
+ TRequestStatus status;
+ TSockAddr dummy;
+ if (d->socketType == QAbstractSocket::UdpSocket) {
+ //RecvOneOrMore() can only be used with stream-interfaced connected sockets; datagram interface sockets will return KErrNotSupported.
+ d->nativeSocket.RecvFrom(buffer, dummy, 0, status);
+ } else {
+ d->nativeSocket.RecvOneOrMore(buffer, 0, status, received);
+ }
+ User::WaitForRequest(status); //Non blocking receive
+ TInt err = status.Int();
+ int r = buffer.Length();
+
+ if (err == KErrWouldBlock) {
+ // No data was available for reading
+ r = -2;
+ } else if (err != KErrNone) {
+ d->setError(err);
+ close();
+ r = -1;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i (err = %d)",
+ data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),
+ maxSize, r, err);
+#endif
+
+ return qint64(r);
+}
+
+int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+{
+ bool readyRead = false;
+ bool readyWrite = false;
+ if (selectForRead)
+ return nativeSelect(timeout, true, false, &readyRead, &readyWrite);
+ else
+ return nativeSelect(timeout, false, true, &readyRead, &readyWrite);
+}
+
+/*!
+ \internal
+ \param timeout timeout in milliseconds
+ \param checkRead caller is interested if the socket is ready to read
+ \param checkWrite caller is interested if the socket is ready for write
+ \param selectForRead (out) should set to true if ready to read
+ \param selectForWrite (out) should set to true if ready to write
+ \return 0 on timeout, >0 on success, <0 on error
+ */
+int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const
+{
+ //cancel asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->Cancel();
+
+ TPckgBuf<TUint> selectFlags;
+ selectFlags() = KSockSelectExcept;
+ if (checkRead)
+ selectFlags() |= KSockSelectRead;
+ if (checkWrite)
+ selectFlags() |= KSockSelectWrite;
+ TInt err;
+ if (timeout == 0) {
+ //if timeout is zero, poll
+ err = nativeSocket.GetOpt(KSOSelectPoll, KSOLSocket, selectFlags);
+ } else {
+ TRequestStatus selectStat;
+ nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket);
+
+ if (timeout < 0)
+ User::WaitForRequest(selectStat); //negative means no timeout
+ else {
+ if (!selectTimer.Handle())
+ qt_symbian_throwIfError(selectTimer.CreateLocal());
+ TRequestStatus timerStat;
+ selectTimer.HighRes(timerStat, timeout * 1000);
+ User::WaitForRequest(timerStat, selectStat);
+ if (selectStat == KRequestPending) {
+ nativeSocket.CancelIoctl();
+ //CancelIoctl completes the request (most likely with KErrCancel)
+ //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic)
+ User::WaitForRequest(selectStat);
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest();
+ #ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout";
+ #endif
+ return 0; //timeout
+ } else {
+ selectTimer.Cancel();
+ User::WaitForRequest(timerStat);
+ }
+ }
+
+ #ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags();
+ #endif
+ err = selectStat.Int();
+ }
+
+ if (!err && (selectFlags() & KSockSelectExcept)) {
+ nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select last error" << err;
+#endif
+ }
+ if (err) {
+ //TODO: avoidable cast?
+ //set the error here, because read won't always return the same error again as select.
+ const_cast<QSymbianSocketEnginePrivate*>(this)->setError(err);
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest(); //TODO: in error case should we restart or not?
+ return err;
+ }
+ if (checkRead && (selectFlags() & KSockSelectRead)) {
+ Q_ASSERT(selectForRead);
+ *selectForRead = true;
+ }
+ if (checkWrite && (selectFlags() & KSockSelectWrite)) {
+ Q_ASSERT(selectForWrite);
+ *selectForWrite = true;
+ }
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest();
+ return 1;
+}
+
+bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::joinMulticastGroup(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6JoinGroup);
+}
+
+bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::leaveMulticastGroup(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6LeaveGroup);
+}
+
+bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface,
+ TUint operation)
+{
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QSymbianSocketEnginePrivate::multicastGroupMembershipHelper" << groupAddress << iface << operation;
+#endif
+ //translate address
+ TPckgBuf<TIp6Mreq> option;
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(option().iAddr.u.iAddr8, ip6.c, 16);
+ } else {
+ TInetAddr wrapped;
+ wrapped.SetAddress(groupAddress.toIPv4Address());
+ wrapped.ConvertToV4Mapped();
+ option().iAddr = wrapped.Ip6Address();
+ }
+ option().iInterface = iface.index();
+ //join or leave group
+ TInt err = nativeSocket.SetOpt(operation, KSolInetIp, option);
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "address" << qt_prettyDebug((const char *)(option().iAddr.u.iAddr8), 16, 16);
+ qDebug() << "interface" << option().iInterface;
+ qDebug() << "error" << err;
+#endif
+ if (err) {
+ setError(err);
+ }
+ return (KErrNone == err);
+}
+
+QNetworkInterface QSymbianSocketEngine::multicastInterface() const
+{
+ //TODO
+ const Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::multicastInterface(), QNetworkInterface());
+ Q_CHECK_TYPE(QSymbianSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
+ return QNetworkInterface();
+}
+
+bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
+{
+ //TODO - this is possibly a unix'ism as the RConnection on which the socket was created is probably controlling this
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setMulticastInterface(), false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
+ return false;
+}
+
+bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address)
+{
+ if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6)
+ return true;
+
+#if !defined(QT_NO_NETWORKPROXY)
+ QObject *parent = q_func()->parent();
+ QNetworkProxy proxy;
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) {
+ proxy = socket->proxy();
+ } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) {
+ proxy = server->proxy();
+ } else {
+ // no parent -> no proxy
+ return true;
+ }
+
+ if (proxy.type() == QNetworkProxy::DefaultProxy)
+ proxy = QNetworkProxy::applicationProxy();
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy &&
+ proxy.type() != QNetworkProxy::NoProxy) {
+ // QSymbianSocketEngine doesn't do proxies
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ InvalidProxyTypeString);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+// FIXME this is also in QNativeSocketEngine, unify it
+/*! \internal
+
+ Sets the error and error string if not set already. The only
+ interesting error is the first one that occurred, and not the last
+ one.
+*/
+void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
+{
+ if (hasSetSocketError) {
+ // Only set socket errors once for one engine; expect the
+ // socket to recreate its engine after an error. Note: There's
+ // one exception: SocketError(11) bypasses this as it's purely
+ // a temporary internal error condition.
+ // Another exception is the way the waitFor*() functions set
+ // an error when a timeout occurs. After the call to setError()
+ // they reset the hasSetSocketError to false
+ return;
+ }
+ if (error != QAbstractSocket::SocketError(11))
+ hasSetSocketError = true;
+
+ socketError = error;
+
+ switch (errorString) {
+ case NonBlockingInitFailedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to initialize non-blocking socket");
+ break;
+ case BroadcastingInitFailedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to initialize broadcast socket");
+ break;
+ case NoIpV6ErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support");
+ break;
+ case RemoteHostClosedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The remote host closed the connection");
+ break;
+ case TimeOutErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network operation timed out");
+ break;
+ case ResourceErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Out of resources");
+ break;
+ case OperationUnsupportedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unsupported socket operation");
+ break;
+ case ProtocolUnsupportedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Protocol type not supported");
+ break;
+ case InvalidSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Invalid socket descriptor");
+ break;
+ case HostUnreachableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Host unreachable");
+ break;
+ case NetworkUnreachableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network unreachable");
+ break;
+ case AccessErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Permission denied");
+ break;
+ case ConnectionTimeOutErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Connection timed out");
+ break;
+ case ConnectionRefusedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Connection refused");
+ break;
+ case AddressInuseErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The bound address is already in use");
+ break;
+ case AddressNotAvailableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is not available");
+ break;
+ case AddressProtectedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is protected");
+ break;
+ case DatagramTooLargeErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Datagram was too large to send");
+ break;
+ case SendDatagramErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to send a message");
+ break;
+ case ReceiveDatagramErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to receive a message");
+ break;
+ case WriteErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to write");
+ break;
+ case ReadErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network error");
+ break;
+ case PortInuseErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Another socket is already listening on the same port");
+ break;
+ case NotSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Operation on non-socket");
+ break;
+ case InvalidProxyTypeString:
+ socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation");
+ break;
+ case InvalidAddressErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is invalid for this operation");
+ break;
+ case SessionNotOpenErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The specified network session is not opened");
+ break;
+ case UnknownSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unknown error");
+ break;
+ }
+}
+
+void QSymbianSocketEnginePrivate::setError(TInt symbianError)
+{
+ switch (symbianError) {
+ case KErrDisconnected:
+ case KErrEof:
+ case KErrConnectionTerminated: //interface stopped externally - RConnection::Stop(EStopAuthoritative)
+ setError(QAbstractSocket::RemoteHostClosedError,
+ QSymbianSocketEnginePrivate::RemoteHostClosedErrorString);
+ break;
+ case KErrNetUnreach:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::NetworkUnreachableErrorString);
+ break;
+ case KErrHostUnreach:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::HostUnreachableErrorString);
+ break;
+ case KErrNoProtocolOpt:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::ProtocolUnsupportedErrorString);
+ break;
+ case KErrInUse:
+ setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
+ break;
+ case KErrPermissionDenied:
+ setError(QAbstractSocket::SocketAccessError, AccessErrorString);
+ break;
+ case KErrNotSupported:
+ setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
+ break;
+ case KErrNoMemory:
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
+ case KErrCouldNotConnect:
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ break;
+ case KErrTimedOut:
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ break;
+ case KErrBadName:
+ setError(QAbstractSocket::NetworkError, InvalidAddressErrorString);
+ break;
+ default:
+ socketError = QAbstractSocket::NetworkError;
+ socketErrorString = QSystemError(symbianError, QSystemError::NativeError).toString();
+ break;
+ }
+ hasSetSocketError = true;
+}
+
+void QSymbianSocketEngine::startNotifications()
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::startNotifications" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+#endif
+ if (!d->asyncSelect && (d->readNotificationsEnabled || d->writeNotificationsEnabled || d->exceptNotificationsEnabled)) {
+ if (d->threadData->eventDispatcher) {
+ d->asyncSelect = q_check_ptr(new QAsyncSelect(
+ static_cast<QEventDispatcherSymbian*> (d->threadData->eventDispatcher), d->nativeSocket,
+ this));
+ } else {
+ // call again when event dispatcher has been created
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
+ }
+ }
+ if (d->asyncSelect)
+ d->asyncSelect->IssueRequest();
+}
+
+bool QSymbianSocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isReadNotificationEnabled(), false);
+ return d->readNotificationsEnabled;
+}
+
+void QSymbianSocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReadNotificationEnabled(), Q_VOID);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->readNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isWriteNotificationEnabled(), false);
+ return d->writeNotificationsEnabled;
+}
+
+void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setWriteNotificationEnabled(), Q_VOID);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->writeNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isExceptionNotificationEnabled(), false);
+ return d->exceptNotificationsEnabled;
+ return false;
+}
+
+void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setExceptionNotificationEnabled(), Q_VOID);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->exceptNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForRead(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForRead(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, true);
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+bool QSymbianSocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, false);
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+bool QSymbianSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForReadOrWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite);
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+qint64 QSymbianSocketEngine::bytesToWrite() const
+{
+ // This is what the QNativeSocketEngine does
+ return 0;
+}
+
+bool QSymbianSocketEngine::event(QEvent* ev)
+{
+ Q_D(QSymbianSocketEngine);
+ if (ev->type() == QEvent::ThreadChange) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::event - ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+#endif
+ if (d->asyncSelect) {
+ delete d->asyncSelect;
+ d->asyncSelect = 0;
+ // recreate select in new thread (because it is queued, the method is called in the new thread context)
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
+ }
+ d->selectTimer.Close();
+ return true;
+ }
+ return QAbstractSocketEngine::event(ev);
+}
+
+QAsyncSelect::QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent)
+ : QActiveObject(CActive::EPriorityStandard, dispatcher),
+ m_inSocketEvent(false),
+ m_deleteLater(false),
+ m_socket(sock),
+ m_selectFlags(0),
+ engine(parent)
+{
+ CActiveScheduler::Add(this);
+}
+
+QAsyncSelect::~QAsyncSelect()
+{
+ Cancel();
+}
+
+void QAsyncSelect::DoCancel()
+{
+ m_socket.CancelIoctl();
+}
+
+void QAsyncSelect::RunL()
+{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+//RunError is called by the active scheduler if RunL leaves.
+//Typically this will happen if a std::bad_alloc propagates down from the application
+TInt QAsyncSelect::RunError(TInt aError)
+{
+ if (engine) {
+ QT_TRY {
+ engine->d_func()->setError(aError);
+ if (engine->isExceptionNotificationEnabled())
+ engine->exceptionNotification();
+ if (engine->isReadNotificationEnabled())
+ engine->readNotification();
+ }
+ QT_CATCH(...) {}
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::RunError" << aError;
+#endif
+ return KErrNone;
+}
+
+void QAsyncSelect::run()
+{
+ //when event loop disabled socket events, defer until later
+ if (maybeDeferSocketEvent())
+ return;
+ m_inSocketEvent = true;
+ m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested
+ //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the
+ //datagram is larger than the read buffer - Qt doesn't need to use this.
+ if (engine && engine->isReadNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) {
+ engine->readNotification();
+ }
+ if (engine && engine->isWriteNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) {
+ if (engine->state() == QAbstractSocket::ConnectingState)
+ engine->connectionNotification();
+ else
+ engine->writeNotification();
+ }
+ if (engine && engine->isExceptionNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) {
+ engine->exceptionNotification();
+ }
+ m_inSocketEvent = false;
+ if (m_deleteLater) {
+ delete this;
+ return;
+ }
+ // select again (unless disabled by one of the callbacks)
+ IssueRequest();
+}
+
+void QAsyncSelect::deleteLater()
+{
+ if (m_inSocketEvent) {
+ engine = 0;
+ m_deleteLater = true;
+ } else {
+ delete this;
+ }
+}
+
+void QAsyncSelect::IssueRequest()
+{
+ if (m_inSocketEvent)
+ return; //prevent thrashing during a callback - socket engine enables/disables multiple notifiers
+ TUint selectFlags = 0;
+ if (engine->isReadNotificationEnabled())
+ selectFlags |= KSockSelectRead;
+ if (engine->isWriteNotificationEnabled())
+ selectFlags |= KSockSelectWrite;
+ if (engine->isExceptionNotificationEnabled())
+ selectFlags |= KSockSelectExcept;
+ if (selectFlags != m_selectFlags) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::IssueRequest() - select flags" << m_selectFlags << "->" << selectFlags;
+#endif
+ Cancel();
+ m_selectFlags = selectFlags;
+ }
+ if (m_selectFlags && !IsActive()) {
+ //always request errors (write notification does not complete on connect errors)
+ m_selectBuf() = m_selectFlags | KSockSelectExcept;
+ m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket);
+ SetActive();
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::IssueRequest() - IsActive" << IsActive();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h
new file mode 100644
index 0000000000..85ab54af12
--- /dev/null
+++ b/src/network/socket/qsymbiansocketengine_p.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSYMBIANSOCKETENGINE_P_H
+#define QSYMBIANSOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+#include "QtNetwork/qhostaddress.h"
+#include "private/qabstractsocketengine_p.h"
+#include "qplatformdefs.h"
+
+#include <private/qeventdispatcher_symbian_p.h>
+#include <unistd.h>
+#include <es_sock.h>
+#include <in_sock.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QSymbianSocketEnginePrivate;
+class QNetworkInterface;
+
+class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+ friend class QAsyncSelect;
+public:
+ QSymbianSocketEngine(QObject *parent = 0);
+ ~QSymbianSocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ int socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+
+ qint64 bytesAvailable() const;
+
+ qint64 read(char *data, qint64 maxlen);
+ qint64 write(const char *data, qint64 len);
+
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
+ quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
+ quint16 port);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+
+ qint64 bytesToWrite() const;
+
+ qint64 receiveBufferSize() const;
+ void setReceiveBufferSize(qint64 bufferSize);
+
+ qint64 sendBufferSize() const;
+ void setSendBufferSize(qint64 bufferSize);
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+ bool event(QEvent* ev);
+
+ Q_INVOKABLE void startNotifications();
+
+public Q_SLOTS:
+ // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it
+ // non-virtual override;
+ void connectionNotification();
+
+private:
+ Q_DECLARE_PRIVATE(QSymbianSocketEngine)
+ Q_DISABLE_COPY(QSymbianSocketEngine)
+};
+
+class QSocketNotifier;
+
+class QReadNotifier;
+class QWriteNotifier;
+class QExceptionNotifier;
+class QAsyncSelect : public QActiveObject
+{
+public:
+ QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent);
+ ~QAsyncSelect();
+
+ void deleteLater();
+ void IssueRequest();
+
+ void refresh();
+
+protected:
+ void DoCancel();
+ void RunL();
+ void run();
+ TInt RunError(TInt aError);
+
+private:
+ bool m_inSocketEvent;
+ bool m_deleteLater;
+ RSocket &m_socket;
+
+ TUint m_selectFlags;
+ TPckgBuf<TUint> m_selectBuf; //in & out IPC buffer
+ QSymbianSocketEngine *engine;
+};
+
+class QSymbianSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QSymbianSocketEngine)
+public:
+ QSymbianSocketEnginePrivate();
+ ~QSymbianSocketEnginePrivate();
+
+ int socketDescriptor;
+ mutable RSocket nativeSocket;
+ // From QtCore:
+ RSocketServ& socketServer;
+ mutable RTimer selectTimer;
+
+ bool readNotificationsEnabled;
+ bool writeNotificationsEnabled;
+ bool exceptNotificationsEnabled;
+ QAsyncSelect* asyncSelect;
+
+ // FIXME this is duplicated from qnativesocketengine_p.h
+ enum ErrorString {
+ NonBlockingInitFailedErrorString,
+ BroadcastingInitFailedErrorString,
+ NoIpV6ErrorString,
+ RemoteHostClosedErrorString,
+ TimeOutErrorString,
+ ResourceErrorString,
+ OperationUnsupportedErrorString,
+ ProtocolUnsupportedErrorString,
+ InvalidSocketErrorString,
+ HostUnreachableErrorString,
+ NetworkUnreachableErrorString,
+ AccessErrorString,
+ ConnectionTimeOutErrorString,
+ ConnectionRefusedErrorString,
+ AddressInuseErrorString,
+ AddressNotAvailableErrorString,
+ AddressProtectedErrorString,
+ DatagramTooLargeErrorString,
+ SendDatagramErrorString,
+ ReceiveDatagramErrorString,
+ WriteErrorString,
+ ReadErrorString,
+ PortInuseErrorString,
+ NotSocketErrorString,
+ InvalidProxyTypeString,
+ //symbian specific
+ InvalidAddressErrorString,
+ SessionNotOpenErrorString,
+
+ UnknownSocketErrorString = -1
+ };
+ void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
+
+ void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr);
+ void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr);
+ void setError(TInt symbianError);
+
+ int nativeSelect(int timeout, bool selectForRead) const;
+ int nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const;
+
+ bool createNewSocket(QAbstractSocket::SocketType socketType,
+ QAbstractSocket::NetworkLayerProtocol socketProtocol);
+
+ bool checkProxy(const QHostAddress &address);
+ bool fetchConnectionParameters();
+
+ bool multicastGroupMembershipHelper(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface,
+ TUint operation);
+ static bool translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSYMBIANSOCKETENGINE_P_H
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
new file mode 100644
index 0000000000..5a60764a3b
--- /dev/null
+++ b/src/network/socket/qtcpserver.cpp
@@ -0,0 +1,691 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QTCPSERVER_DEBUG
+
+/*! \class QTcpServer
+
+ \brief The QTcpServer class provides a TCP-based server.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ This class makes it possible to accept incoming TCP connections.
+ You can specify the port or have QTcpServer pick one
+ automatically. You can listen on a specific address or on all the
+ machine's addresses.
+
+ Call listen() to have the server listen for incoming connections.
+ The newConnection() signal is then emitted each time a client
+ connects to the server.
+
+ Call nextPendingConnection() to accept the pending connection as
+ a connected QTcpSocket. The function returns a pointer to a
+ QTcpSocket in QAbstractSocket::ConnectedState that you can use for
+ communicating with the client.
+
+ If an error occurs, serverError() returns the type of error, and
+ errorString() can be called to get a human readable description of
+ what happened.
+
+ When listening for connections, the address and port on which the
+ server is listening are available as serverAddress() and
+ serverPort().
+
+ Calling close() makes QTcpServer stop listening for incoming
+ connections.
+
+ Although QTcpServer is mostly designed for use with an event
+ loop, it's possible to use it without one. In that case, you must
+ use waitForNewConnection(), which blocks until either a
+ connection is available or a timeout expires.
+
+ \section1 Symbian Platform Security Requirements
+
+ On Symbian, processes which use this class must have the
+ \c NetworkServices platform security capability. If the client
+ process lacks this capability, it will lead to a panic.
+
+ Platform security capabilities are added via the
+ \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
+ qmake variable.
+
+ \sa QTcpSocket, {Fortune Server Example}, {Threaded Fortune Server Example},
+ {Loopback Example}, {Torrent Example}
+*/
+
+/*! \fn void QTcpServer::newConnection()
+
+ This signal is emitted every time a new connection is available.
+
+ \sa hasPendingConnections(), nextPendingConnection()
+*/
+
+#include "private/qobject_p.h"
+#include "qalgorithms.h"
+#include "qhostaddress.h"
+#include "qlist.h"
+#include "qpointer.h"
+#include "qabstractsocketengine_p.h"
+#include "qtcpserver.h"
+#include "qtcpsocket.h"
+#include "qnetworkproxy.h"
+
+QT_BEGIN_NAMESPACE
+
+#define Q_CHECK_SOCKETENGINE(returnValue) do { \
+ if (!d->socketEngine) { \
+ return returnValue; \
+ } } while (0)
+
+class QTcpServerPrivate : public QObjectPrivate, public QAbstractSocketEngineReceiver
+{
+ Q_DECLARE_PUBLIC(QTcpServer)
+public:
+ QTcpServerPrivate();
+ ~QTcpServerPrivate();
+
+ QList<QTcpSocket *> pendingConnections;
+
+ quint16 port;
+ QHostAddress address;
+
+ QAbstractSocket::SocketState state;
+ QAbstractSocketEngine *socketEngine;
+
+ QAbstractSocket::SocketError serverSocketError;
+ QString serverSocketErrorString;
+
+ int maxConnections;
+
+#ifndef QT_NO_NETWORKPROXY
+ QNetworkProxy proxy;
+ QNetworkProxy resolveProxy(const QHostAddress &address, quint16 port);
+#endif
+
+ // from QAbstractSocketEngineReceiver
+ void readNotification();
+ inline void writeNotification() {}
+ inline void exceptionNotification() {}
+ inline void connectionNotification() {}
+#ifndef QT_NO_NETWORKPROXY
+ inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *) {}
+#endif
+
+};
+
+/*! \internal
+*/
+QTcpServerPrivate::QTcpServerPrivate()
+ : port(0)
+ , state(QAbstractSocket::UnconnectedState)
+ , socketEngine(0)
+ , serverSocketError(QAbstractSocket::UnknownSocketError)
+ , maxConnections(30)
+{
+}
+
+/*! \internal
+*/
+QTcpServerPrivate::~QTcpServerPrivate()
+{
+}
+
+#ifndef QT_NO_NETWORKPROXY
+/*! \internal
+
+ Resolve the proxy to its final value.
+*/
+QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint16 port)
+{
+ if (address == QHostAddress::LocalHost ||
+ address == QHostAddress::LocalHostIPv6)
+ return QNetworkProxy::NoProxy;
+
+ QList<QNetworkProxy> proxies;
+ if (proxy.type() != QNetworkProxy::DefaultProxy) {
+ // a non-default proxy was set with setProxy
+ proxies << proxy;
+ } else {
+ // try the application settings instead
+ QNetworkProxyQuery query(port, QString(), QNetworkProxyQuery::TcpServer);
+ proxies = QNetworkProxyFactory::proxyForQuery(query);
+ }
+
+ // return the first that we can use
+ foreach (const QNetworkProxy &p, proxies) {
+ if (p.capabilities() & QNetworkProxy::ListeningCapability)
+ return p;
+ }
+
+ // no proxy found
+ // DefaultProxy will raise an error
+ return QNetworkProxy(QNetworkProxy::DefaultProxy);
+}
+#endif
+
+/*! \internal
+*/
+void QTcpServerPrivate::readNotification()
+{
+ Q_Q(QTcpServer);
+ for (;;) {
+ if (pendingConnections.count() >= maxConnections) {
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServerPrivate::_q_processIncomingConnection() too many connections");
+#endif
+ if (socketEngine->isReadNotificationEnabled())
+ socketEngine->setReadNotificationEnabled(false);
+ return;
+ }
+
+ int descriptor = socketEngine->accept();
+ if (descriptor == -1)
+ break;
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServerPrivate::_q_processIncomingConnection() accepted socket %i", descriptor);
+#endif
+ q->incomingConnection(descriptor);
+
+ QPointer<QTcpServer> that = q;
+ emit q->newConnection();
+ if (!that || !q->isListening())
+ return;
+ }
+}
+
+/*!
+ Constructs a QTcpServer object.
+
+ \a parent is passed to the QObject constructor.
+
+ \sa listen(), setSocketDescriptor()
+*/
+QTcpServer::QTcpServer(QObject *parent)
+ : QObject(*new QTcpServerPrivate, parent)
+{
+}
+
+/*!
+ Destroys the QTcpServer object. If the server is listening for
+ connections, the socket is automatically closed.
+
+ Any client \l{QTcpSocket}s that are still connected must either
+ disconnect or be reparented before the server is deleted.
+
+ \sa close()
+*/
+QTcpServer::~QTcpServer()
+{
+ close();
+}
+
+/*!
+ Tells the server to listen for incoming connections on address \a
+ address and port \a port. If \a port is 0, a port is chosen
+ automatically. If \a address is QHostAddress::Any, the server
+ will listen on all network interfaces.
+
+ Returns true on success; otherwise returns false.
+
+ \sa isListening()
+*/
+bool QTcpServer::listen(const QHostAddress &address, quint16 port)
+{
+ Q_D(QTcpServer);
+ if (d->state == QAbstractSocket::ListeningState) {
+ qWarning("QTcpServer::listen() called when already listening");
+ return false;
+ }
+
+ QAbstractSocket::NetworkLayerProtocol proto = address.protocol();
+
+#ifdef QT_NO_NETWORKPROXY
+ static const QNetworkProxy &proxy = *(QNetworkProxy *)0;
+#else
+ QNetworkProxy proxy = d->resolveProxy(address, port);
+#endif
+
+ delete d->socketEngine;
+ d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this);
+ if (!d->socketEngine) {
+ d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError;
+ d->serverSocketErrorString = tr("Operation on socket is not supported");
+ return false;
+ }
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
+ if (!d->socketEngine->initialize(QAbstractSocket::TcpSocket, proto)) {
+ d->serverSocketError = d->socketEngine->error();
+ d->serverSocketErrorString = d->socketEngine->errorString();
+ return false;
+ }
+
+#if defined(Q_OS_UNIX)
+ // Under Unix, we want to be able to bind to the port, even if a socket on
+ // the same address-port is in TIME_WAIT. Under Windows this is possible
+ // anyway -- furthermore, the meaning of reusable on Windows is different:
+ // it means that you can use the same address-port for multiple listening
+ // sockets.
+ // Don't abort though if we can't set that option. For example the socks
+ // engine doesn't support that option, but that shouldn't prevent us from
+ // trying to bind/listen.
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+#endif
+
+ if (!d->socketEngine->bind(address, port)) {
+ d->serverSocketError = d->socketEngine->error();
+ d->serverSocketErrorString = d->socketEngine->errorString();
+ return false;
+ }
+
+ if (!d->socketEngine->listen()) {
+ d->serverSocketError = d->socketEngine->error();
+ d->serverSocketErrorString = d->socketEngine->errorString();
+ return false;
+ }
+
+ d->socketEngine->setReceiver(d);
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ d->state = QAbstractSocket::ListeningState;
+ d->address = d->socketEngine->localAddress();
+ d->port = d->socketEngine->localPort();
+
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServer::listen(%i, \"%s\") == true (listening on port %i)", port,
+ address.toString().toLatin1().constData(), d->socketEngine->localPort());
+#endif
+ return true;
+}
+
+/*!
+ Returns true if the server is currently listening for incoming
+ connections; otherwise returns false.
+
+ \sa listen()
+*/
+bool QTcpServer::isListening() const
+{
+ Q_D(const QTcpServer);
+ Q_CHECK_SOCKETENGINE(false);
+ return d->socketEngine->state() == QAbstractSocket::ListeningState;
+}
+
+/*!
+ Closes the server. The server will no longer listen for incoming
+ connections.
+
+ \sa listen()
+*/
+void QTcpServer::close()
+{
+ Q_D(QTcpServer);
+
+ qDeleteAll(d->pendingConnections);
+ d->pendingConnections.clear();
+
+ if (d->socketEngine) {
+ d->socketEngine->close();
+ QT_TRY {
+ d->socketEngine->deleteLater();
+ } QT_CATCH(const std::bad_alloc &) {
+ // in out of memory situations, the socketEngine
+ // will be deleted in ~QTcpServer (it's a child-object of this)
+ }
+ d->socketEngine = 0;
+ }
+
+ d->state = QAbstractSocket::UnconnectedState;
+}
+
+/*!
+ Returns the native socket descriptor the server uses to listen
+ for incoming instructions, or -1 if the server is not listening.
+
+ If the server is using QNetworkProxy, the returned descriptor may
+ not be usable with native socket functions.
+
+ \sa setSocketDescriptor(), isListening()
+*/
+int QTcpServer::socketDescriptor() const
+{
+ Q_D(const QTcpServer);
+ Q_CHECK_SOCKETENGINE(-1);
+ return d->socketEngine->socketDescriptor();
+}
+
+/*!
+ Sets the socket descriptor this server should use when listening
+ for incoming connections to \a socketDescriptor. Returns true if
+ the socket is set successfully; otherwise returns false.
+
+ The socket is assumed to be in listening state.
+
+ \sa socketDescriptor(), isListening()
+*/
+bool QTcpServer::setSocketDescriptor(int socketDescriptor)
+{
+ Q_D(QTcpServer);
+ if (isListening()) {
+ qWarning("QTcpServer::setSocketDescriptor() called when already listening");
+ return false;
+ }
+
+ if (d->socketEngine)
+ delete d->socketEngine;
+ d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this);
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
+ if (!d->socketEngine->initialize(socketDescriptor, QAbstractSocket::ListeningState)) {
+ d->serverSocketError = d->socketEngine->error();
+ d->serverSocketErrorString = d->socketEngine->errorString();
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServer::setSocketDescriptor(%i) failed (%s)", socketDescriptor,
+ d->serverSocketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+ d->socketEngine->setReceiver(d);
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ d->state = d->socketEngine->state();
+ d->address = d->socketEngine->localAddress();
+ d->port = d->socketEngine->localPort();
+
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServer::setSocketDescriptor(%i) succeeded.", socketDescriptor);
+#endif
+ return true;
+}
+
+/*!
+ Returns the server's port if the server is listening for
+ connections; otherwise returns 0.
+
+ \sa serverAddress(), listen()
+*/
+quint16 QTcpServer::serverPort() const
+{
+ Q_D(const QTcpServer);
+ Q_CHECK_SOCKETENGINE(0);
+ return d->socketEngine->localPort();
+}
+
+/*!
+ Returns the server's address if the server is listening for
+ connections; otherwise returns QHostAddress::Null.
+
+ \sa serverPort(), listen()
+*/
+QHostAddress QTcpServer::serverAddress() const
+{
+ Q_D(const QTcpServer);
+ Q_CHECK_SOCKETENGINE(QHostAddress(QHostAddress::Null));
+ return d->socketEngine->localAddress();
+}
+
+/*!
+ Waits for at most \a msec milliseconds or until an incoming
+ connection is available. Returns true if a connection is
+ available; otherwise returns false. If the operation timed out
+ and \a timedOut is not 0, *\a timedOut will be set to true.
+
+ This is a blocking function call. Its use is disadvised in a
+ single-threaded GUI application, since the whole application will
+ stop responding until the function returns.
+ waitForNewConnection() is mostly useful when there is no event
+ loop available.
+
+ The non-blocking alternative is to connect to the newConnection()
+ signal.
+
+ If msec is -1, this function will not time out.
+
+ \sa hasPendingConnections(), nextPendingConnection()
+*/
+bool QTcpServer::waitForNewConnection(int msec, bool *timedOut)
+{
+ Q_D(QTcpServer);
+ if (d->state != QAbstractSocket::ListeningState)
+ return false;
+
+ if (!d->socketEngine->waitForRead(msec, timedOut)) {
+ d->serverSocketError = d->socketEngine->error();
+ d->serverSocketErrorString = d->socketEngine->errorString();
+ return false;
+ }
+
+ if (timedOut && *timedOut)
+ return false;
+
+ d->readNotification();
+
+ return true;
+}
+
+/*!
+ Returns true if the server has a pending connection; otherwise
+ returns false.
+
+ \sa nextPendingConnection(), setMaxPendingConnections()
+*/
+bool QTcpServer::hasPendingConnections() const
+{
+ return !d_func()->pendingConnections.isEmpty();
+}
+
+/*!
+ Returns the next pending connection as a connected QTcpSocket
+ object.
+
+ The socket is created as a child of the server, which means that
+ it is automatically deleted when the QTcpServer object is
+ destroyed. It is still a good idea to delete the object
+ explicitly when you are done with it, to avoid wasting memory.
+
+ 0 is returned if this function is called when there are no pending
+ connections.
+
+ \note The returned QTcpSocket object cannot be used from another
+ thread. If you want to use an incoming connection from another thread,
+ you need to override incomingConnection().
+
+ \sa hasPendingConnections()
+*/
+QTcpSocket *QTcpServer::nextPendingConnection()
+{
+ Q_D(QTcpServer);
+ if (d->pendingConnections.isEmpty())
+ return 0;
+
+ if (!d->socketEngine->isReadNotificationEnabled())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ return d->pendingConnections.takeFirst();
+}
+
+/*!
+ This virtual function is called by QTcpServer when a new
+ connection is available. The \a socketDescriptor argument is the
+ native socket descriptor for the accepted connection.
+
+ The base implementation creates a QTcpSocket, sets the socket
+ descriptor and then stores the QTcpSocket in an internal list of
+ pending connections. Finally newConnection() is emitted.
+
+ Reimplement this function to alter the server's behavior when a
+ connection is available.
+
+ If this server is using QNetworkProxy then the \a socketDescriptor
+ may not be usable with native socket functions, and should only be
+ used with QTcpSocket::setSocketDescriptor().
+
+ \note If you want to handle an incoming connection as a new QTcpSocket
+ object in another thread you have to pass the socketDescriptor
+ to the other thread and create the QTcpSocket object there and
+ use its setSocketDescriptor() method.
+
+ \sa newConnection(), nextPendingConnection(), addPendingConnection()
+*/
+void QTcpServer::incomingConnection(int socketDescriptor)
+{
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServer::incomingConnection(%i)", socketDescriptor);
+#endif
+
+ QTcpSocket *socket = new QTcpSocket(this);
+ socket->setSocketDescriptor(socketDescriptor);
+ addPendingConnection(socket);
+}
+
+/*!
+ This function is called by QTcpServer::incomingConnection()
+ to add the \a socket to the list of pending incoming connections.
+
+ \note Don't forget to call this member from reimplemented
+ incomingConnection() if you do not want to break the
+ Pending Connections mechanism.
+
+ \sa incomingConnection()
+ \since 4.7
+*/
+void QTcpServer::addPendingConnection(QTcpSocket* socket)
+{
+ d_func()->pendingConnections.append(socket);
+}
+
+/*!
+ Sets the maximum number of pending accepted connections to \a
+ numConnections. QTcpServer will accept no more than \a
+ numConnections incoming connections before
+ nextPendingConnection() is called. By default, the limit is 30
+ pending connections.
+
+ Clients may still able to connect after the server has reached
+ its maximum number of pending connections (i.e., QTcpSocket can
+ still emit the connected() signal). QTcpServer will stop
+ accepting the new connections, but the operating system may
+ still keep them in queue.
+
+ \sa maxPendingConnections(), hasPendingConnections()
+*/
+void QTcpServer::setMaxPendingConnections(int numConnections)
+{
+ d_func()->maxConnections = numConnections;
+}
+
+/*!
+ Returns the maximum number of pending accepted connections. The
+ default is 30.
+
+ \sa setMaxPendingConnections(), hasPendingConnections()
+*/
+int QTcpServer::maxPendingConnections() const
+{
+ return d_func()->maxConnections;
+}
+
+/*!
+ Returns an error code for the last error that occurred.
+
+ \sa errorString()
+*/
+QAbstractSocket::SocketError QTcpServer::serverError() const
+{
+ return d_func()->serverSocketError;
+}
+
+/*!
+ Returns a human readable description of the last error that
+ occurred.
+
+ \sa serverError()
+*/
+QString QTcpServer::errorString() const
+{
+ return d_func()->serverSocketErrorString;
+}
+
+#ifndef QT_NO_NETWORKPROXY
+/*!
+ \since 4.1
+
+ Sets the explicit network proxy for this socket to \a networkProxy.
+
+ To disable the use of a proxy for this socket, use the
+ QNetworkProxy::NoProxy proxy type:
+
+ \snippet doc/src/snippets/code/src_network_socket_qtcpserver.cpp 0
+
+ \sa proxy(), QNetworkProxy
+*/
+void QTcpServer::setProxy(const QNetworkProxy &networkProxy)
+{
+ Q_D(QTcpServer);
+ d->proxy = networkProxy;
+}
+
+/*!
+ \since 4.1
+
+ Returns the network proxy for this socket.
+ By default QNetworkProxy::DefaultProxy is used.
+
+ \sa setProxy(), QNetworkProxy
+*/
+QNetworkProxy QTcpServer::proxy() const
+{
+ Q_D(const QTcpServer);
+ return d->proxy;
+}
+#endif // QT_NO_NETWORKPROXY
+
+QT_END_NAMESPACE
+
+#include "moc_qtcpserver.cpp"
+
diff --git a/src/network/socket/qtcpserver.h b/src/network/socket/qtcpserver.h
new file mode 100644
index 0000000000..4018da6d00
--- /dev/null
+++ b/src/network/socket/qtcpserver.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTCPSERVER_H
+#define QTCPSERVER_H
+
+#include <QtCore/qobject.h>
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qhostaddress.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QTcpServerPrivate;
+#ifndef QT_NO_NETWORKPROXY
+class QNetworkProxy;
+#endif
+class QTcpSocket;
+
+class Q_NETWORK_EXPORT QTcpServer : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QTcpServer(QObject *parent = 0);
+ virtual ~QTcpServer();
+
+ bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
+ void close();
+
+ bool isListening() const;
+
+ void setMaxPendingConnections(int numConnections);
+ int maxPendingConnections() const;
+
+ quint16 serverPort() const;
+ QHostAddress serverAddress() const;
+
+ int socketDescriptor() const;
+ bool setSocketDescriptor(int socketDescriptor);
+
+ bool waitForNewConnection(int msec = 0, bool *timedOut = 0);
+ virtual bool hasPendingConnections() const;
+ virtual QTcpSocket *nextPendingConnection();
+
+ QAbstractSocket::SocketError serverError() const;
+ QString errorString() const;
+
+#ifndef QT_NO_NETWORKPROXY
+ void setProxy(const QNetworkProxy &networkProxy);
+ QNetworkProxy proxy() const;
+#endif
+
+protected:
+ virtual void incomingConnection(int handle);
+ void addPendingConnection(QTcpSocket* socket);
+
+Q_SIGNALS:
+ void newConnection();
+
+private:
+ Q_DISABLE_COPY(QTcpServer)
+ Q_DECLARE_PRIVATE(QTcpServer)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTCPSERVER_H
diff --git a/src/network/socket/qtcpsocket.cpp b/src/network/socket/qtcpsocket.cpp
new file mode 100644
index 0000000000..32edc2f8ab
--- /dev/null
+++ b/src/network/socket/qtcpsocket.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QTCPSOCKET_DEBUG
+
+/*!
+ \class QTcpSocket
+
+ \brief The QTcpSocket class provides a TCP socket.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ TCP (Transmission Control Protocol) is a reliable,
+ stream-oriented, connection-oriented transport protocol. It is
+ especially well suited for continuous transmission of data.
+
+ QTcpSocket is a convenience subclass of QAbstractSocket that
+ allows you to establish a TCP connection and transfer streams of
+ data. See the QAbstractSocket documentation for details.
+
+ \bold{Note:} TCP sockets cannot be opened in QIODevice::Unbuffered mode.
+
+ \section1 Symbian Platform Security Requirements
+
+ On Symbian, processes which use this class must have the
+ \c NetworkServices platform security capability. If the client
+ process lacks this capability, it will result in a panic.
+
+ Platform security capabilities are added via the
+ \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
+ qmake variable.
+
+ \sa QTcpServer, QUdpSocket, QFtp, QNetworkAccessManager,
+ {Fortune Server Example}, {Fortune Client Example},
+ {Threaded Fortune Server Example}, {Blocking Fortune Client Example},
+ {Loopback Example}, {Torrent Example}
+*/
+
+#include "qlist.h"
+#include "qtcpsocket_p.h"
+#include "qtcpsocket.h"
+#include "qhostaddress.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Creates a QTcpSocket object in state \c UnconnectedState.
+
+ \a parent is passed on to the QObject constructor.
+
+ \sa socketType()
+*/
+QTcpSocket::QTcpSocket(QObject *parent)
+ : QAbstractSocket(TcpSocket, *new QTcpSocketPrivate, parent)
+{
+#if defined(QTCPSOCKET_DEBUG)
+ qDebug("QTcpSocket::QTcpSocket()");
+#endif
+ d_func()->isBuffered = true;
+}
+
+/*!
+ Destroys the socket, closing the connection if necessary.
+
+ \sa close()
+*/
+
+QTcpSocket::~QTcpSocket()
+{
+#if defined(QTCPSOCKET_DEBUG)
+ qDebug("QTcpSocket::~QTcpSocket()");
+#endif
+}
+
+/*!
+ \internal
+*/
+QTcpSocket::QTcpSocket(QTcpSocketPrivate &dd, QObject *parent)
+ : QAbstractSocket(TcpSocket, dd, parent)
+{
+ d_func()->isBuffered = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h
new file mode 100644
index 0000000000..a50e0feca9
--- /dev/null
+++ b/src/network/socket/qtcpsocket.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTCPSOCKET_H
+#define QTCPSOCKET_H
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+class QTcpSocketPrivate;
+
+class Q_NETWORK_EXPORT QTcpSocket : public QAbstractSocket
+{
+ Q_OBJECT
+public:
+ explicit QTcpSocket(QObject *parent = 0);
+ virtual ~QTcpSocket();
+
+protected:
+ QTcpSocket(QTcpSocketPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DISABLE_COPY(QTcpSocket)
+ Q_DECLARE_PRIVATE(QTcpSocket)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTCPSOCKET_H
diff --git a/src/network/socket/qtcpsocket_p.h b/src/network/socket/qtcpsocket_p.h
new file mode 100644
index 0000000000..12414df2ed
--- /dev/null
+++ b/src/network/socket/qtcpsocket_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTCPSOCKET_P_H
+#define QTCPSOCKET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/qtcpsocket.h>
+#include <private/qabstractsocket_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTcpSocketPrivate : public QAbstractSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QTcpSocket)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
new file mode 100644
index 0000000000..f8bcd1b967
--- /dev/null
+++ b/src/network/socket/qudpsocket.cpp
@@ -0,0 +1,567 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QUDPSOCKET_DEBUG
+
+/*! \class QUdpSocket
+
+ \reentrant
+ \brief The QUdpSocket class provides a UDP socket.
+
+ \ingroup network
+ \inmodule QtNetwork
+
+ UDP (User Datagram Protocol) is a lightweight, unreliable,
+ datagram-oriented, connectionless protocol. It can be used when
+ reliability isn't important. QUdpSocket is a subclass of
+ QAbstractSocket that allows you to send and receive UDP
+ datagrams.
+
+ The most common way to use this class is to bind to an address and port
+ using bind(), then call writeDatagram() and readDatagram() to transfer
+ data. If you want to use the standard QIODevice functions read(),
+ readLine(), write(), etc., you must first connect the socket directly to a
+ peer by calling connectToHost().
+
+ The socket emits the bytesWritten() signal every time a datagram
+ is written to the network. If you just want to send datagrams,
+ you don't need to call bind().
+
+ The readyRead() signal is emitted whenever datagrams arrive. In
+ that case, hasPendingDatagrams() returns true. Call
+ pendingDatagramSize() to obtain the size of the first pending
+ datagram, and readDatagram() to read it.
+
+ \note An incoming datagram should be read when you receive the readyRead()
+ signal, otherwise this signal will not be emitted for the next datagram.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0
+
+ QUdpSocket also supports UDP multicast. Use joinMulticastGroup() and
+ leaveMulticastGroup() to control group membership, and
+ QAbstractSocket::MulticastTtlOption and
+ QAbstractSocket::MulticastLoopbackOption to set the TTL and loopback socket
+ options. Use setMulticastInterface() to control the outgoing interface for
+ multicast datagrams, and multicastInterface() to query it.
+
+ With QUdpSocket, you can also establish a virtual connection to a
+ UDP server using connectToHost() and then use read() and write()
+ to exchange datagrams without specifying the receiver for each
+ datagram.
+
+ The \l{network/broadcastsender}{Broadcast Sender},
+ \l{network/broadcastreceiver}{Broadcast Receiver},
+ \l{network/multicastsender}{Multicast Sender}, and
+ \l{network/multicastreceiver}{Multicast Receiver} examples illustrate how
+ to use QUdpSocket in applications.
+
+ \section1 Symbian Platform Security Requirements
+
+ On Symbian, processes which use this class must have the
+ \c NetworkServices platform security capability. If the client
+ process lacks this capability, operations will result in a panic.
+
+ Platform security capabilities are added via the
+ \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
+ qmake variable.
+
+ \sa QTcpSocket
+*/
+
+/*! \enum QUdpSocket::BindFlag
+ \since 4.1
+
+ This enum describes the different flags you can pass to modify the
+ behavior of QUdpSocket::bind().
+
+ \note On Symbian OS bind flags behaviour depends on process capabilties.
+ If process has NetworkControl capability, the bind attempt with
+ ReuseAddressHint will always succeed even if the address and port is already
+ bound by another socket with any flags. If process does not have
+ NetworkControl capability, the bind attempt to address and port already
+ bound by another socket will always fail.
+
+ \value ShareAddress Allow other services to bind to the same address
+ and port. This is useful when multiple processes share
+ the load of a single service by listening to the same address and port
+ (e.g., a web server with several pre-forked listeners can greatly
+ improve response time). However, because any service is allowed to
+ rebind, this option is subject to certain security considerations.
+ Note that by combining this option with ReuseAddressHint, you will
+ also allow your service to rebind an existing shared address. On
+ Unix, this is equivalent to the SO_REUSEADDR socket option. On Windows,
+ this option is ignored.
+
+ \value DontShareAddress Bind the address and port exclusively, so that
+ no other services are allowed to rebind. By passing this option to
+ QUdpSocket::bind(), you are guaranteed that on successs, your service
+ is the only one that listens to the address and port. No services are
+ allowed to rebind, even if they pass ReuseAddressHint. This option
+ provides more security than ShareAddress, but on certain operating
+ systems, it requires you to run the server with administrator privileges.
+ On Unix and Mac OS X, not sharing is the default behavior for binding
+ an address and port, so this option is ignored. On Windows, this
+ option uses the SO_EXCLUSIVEADDRUSE socket option.
+
+ \value ReuseAddressHint Provides a hint to QUdpSocket that it should try
+ to rebind the service even if the address and port are already bound by
+ another socket. On Windows, this is equivalent to the SO_REUSEADDR
+ socket option. On Unix, this option is ignored.
+
+ \value DefaultForPlatform The default option for the current platform.
+ On Unix and Mac OS X, this is equivalent to (DontShareAddress
+ + ReuseAddressHint), and on Windows, its equivalent to ShareAddress.
+*/
+
+#include "qhostaddress.h"
+#include "qnetworkinterface.h"
+#include "qabstractsocket_p.h"
+#include "qudpsocket.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_UDPSOCKET
+
+#define QT_CHECK_BOUND(function, a) do { \
+ if (!isValid()) { \
+ qWarning(function" called on a QUdpSocket when not in QUdpSocket::BoundState"); \
+ return (a); \
+ } } while (0)
+
+class QUdpSocketPrivate : public QAbstractSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QUdpSocket)
+
+ bool doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
+ const QHostAddress &remoteAddress);
+public:
+ inline bool ensureInitialized(const QHostAddress &bindAddress, quint16 bindPort)
+ { return doEnsureInitialized(bindAddress, bindPort, QHostAddress()); }
+
+ inline bool ensureInitialized(const QHostAddress &remoteAddress)
+ { return doEnsureInitialized(QHostAddress(), 0, remoteAddress); }
+};
+
+bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
+ const QHostAddress &remoteAddress)
+{
+ const QHostAddress *address = &bindAddress;
+ QAbstractSocket::NetworkLayerProtocol proto = address->protocol();
+ if (proto == QUdpSocket::UnknownNetworkLayerProtocol) {
+ address = &remoteAddress;
+ proto = address->protocol();
+ }
+
+#if defined(QT_NO_IPV6)
+ Q_Q(QUdpSocket);
+ if (proto == QUdpSocket::IPv6Protocol) {
+ socketError = QUdpSocket::UnsupportedSocketOperationError;
+ q->setErrorString(QUdpSocket::tr("This platform does not support IPv6"));
+ return false;
+ }
+#endif
+
+ // now check if the socket engine is initialized and to the right type
+ if (!socketEngine || !socketEngine->isValid()) {
+ resolveProxy(remoteAddress.toString(), bindPort);
+ if (!initSocketLayer(address->protocol()))
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ Creates a QUdpSocket object.
+
+ \a parent is passed to the QObject constructor.
+
+ \sa socketType()
+*/
+QUdpSocket::QUdpSocket(QObject *parent)
+ : QAbstractSocket(UdpSocket, *new QUdpSocketPrivate, parent)
+{
+ d_func()->isBuffered = false;
+}
+
+/*!
+ Destroys the socket, closing the connection if necessary.
+
+ \sa close()
+*/
+QUdpSocket::~QUdpSocket()
+{
+}
+
+/*!
+ Binds this socket to the address \a address and the port \a port.
+ When bound, the signal readyRead() is emitted whenever a UDP
+ datagram arrives on the specified address and port. This function
+ is useful to write UDP servers.
+
+ On success, the functions returns true and the socket enters
+ BoundState; otherwise it returns false.
+
+ The socket is bound using the DefaultForPlatform BindMode.
+
+ \sa readDatagram()
+*/
+bool QUdpSocket::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QUdpSocket);
+ if (!d->ensureInitialized(address, port))
+ return false;
+
+ bool result = d_func()->socketEngine->bind(address, port);
+ d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
+
+ if (!result) {
+ d->socketError = d_func()->socketEngine->error();
+ setErrorString(d_func()->socketEngine->errorString());
+ emit error(d_func()->socketError);
+ return false;
+ }
+
+ d->state = BoundState;
+ d->localAddress = d->socketEngine->localAddress();
+ d->localPort = d->socketEngine->localPort();
+
+ emit stateChanged(d_func()->state);
+ d_func()->socketEngine->setReadNotificationEnabled(true);
+ return true;
+}
+
+/*!
+ \since 4.1
+ \overload
+
+ Binds to \a address on port \a port, using the BindMode \a mode.
+*/
+bool QUdpSocket::bind(const QHostAddress &address, quint16 port, BindMode mode)
+{
+ Q_D(QUdpSocket);
+ if (!d->ensureInitialized(address, port))
+ return false;
+
+#ifdef Q_OS_UNIX
+ if ((mode & ShareAddress) || (mode & ReuseAddressHint))
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+#endif
+#ifdef Q_OS_WIN
+ if (mode & ReuseAddressHint)
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+ if (mode & DontShareAddress)
+ d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
+#endif
+ bool result = d_func()->socketEngine->bind(address, port);
+ d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
+
+ if (!result) {
+ d->socketError = d_func()->socketEngine->error();
+ setErrorString(d_func()->socketEngine->errorString());
+ emit error(d_func()->socketError);
+ return false;
+ }
+
+ d->state = BoundState;
+ d->localAddress = d->socketEngine->localAddress();
+ d->localPort = d->socketEngine->localPort();
+
+ emit stateChanged(d_func()->state);
+ d_func()->socketEngine->setReadNotificationEnabled(true);
+ return true;
+}
+
+/*! \overload
+
+ Binds to QHostAddress:Any on port \a port.
+*/
+bool QUdpSocket::bind(quint16 port)
+{
+ return bind(QHostAddress::Any, port);
+}
+
+/*!
+ \since 4.1
+ \overload
+
+ Binds to QHostAddress:Any on port \a port, using the BindMode \a mode.
+*/
+bool QUdpSocket::bind(quint16 port, BindMode mode)
+{
+ return bind(QHostAddress::Any, port, mode);
+}
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+/*!
+ \since 4.8
+
+ Joins the the multicast group specified by \a groupAddress on the default
+ interface chosen by the operating system. The socket must be in BoundState,
+ otherwise an error occurs.
+
+ This function returns true if successful; otherwise it returns false
+ and sets the socket error accordingly.
+
+ \sa leaveMulticastGroup()
+*/
+bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress)
+{
+ return joinMulticastGroup(groupAddress, QNetworkInterface());
+}
+
+/*!
+ \since 4.8
+ \overload
+
+ Joins the multicast group address \a groupAddress on the interface \a
+ iface.
+
+ \sa leaveMulticastGroup()
+*/
+bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QUdpSocket);
+ QT_CHECK_BOUND("QUdpSocket::joinMulticastGroup()", false);
+ return d->socketEngine->joinMulticastGroup(groupAddress, iface);
+}
+
+/*!
+ \since 4.8
+
+ Leaves the multicast group specified by \a groupAddress on the default
+ interface chosen by the operating system. The socket must be in BoundState,
+ otherwise an error occurs.
+
+ This function returns true if successful; otherwise it returns false and
+ sets the socket error accordingly.
+
+ \sa joinMulticastGroup()
+*/
+bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress)
+{
+ return leaveMulticastGroup(groupAddress, QNetworkInterface());
+}
+
+/*!
+ \since 4.8
+ \overload
+
+ Leaves the multicast group specified by \a groupAddress on the interface \a
+ iface.
+
+ \sa joinMulticastGroup()
+*/
+bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ QT_CHECK_BOUND("QUdpSocket::leaveMulticastGroup()", false);
+ return d_func()->socketEngine->leaveMulticastGroup(groupAddress, iface);
+}
+
+/*!
+ \since 4.8
+
+ Returns the interface for the outgoing interface for multicast datagrams.
+ This corresponds to the IP_MULTICAST_IF socket option for IPv4 sockets and
+ the IPV6_MULTICAST_IF socket option for IPv6 sockets. If no interface has
+ been previously set, this function returns an invalid QNetworkInterface.
+ The socket must be in BoundState, otherwise an invalid QNetworkInterface is
+ returned.
+
+ \sa setMulticastInterface()
+*/
+QNetworkInterface QUdpSocket::multicastInterface() const
+{
+ Q_D(const QUdpSocket);
+ QT_CHECK_BOUND("QUdpSocket::multicastInterface()", QNetworkInterface());
+ return d->socketEngine->multicastInterface();
+}
+
+/*!
+ \since 4.8
+
+ Sets the outgoing interface for multicast datagrams to the interface \a
+ iface. This corresponds to the IP_MULTICAST_IF socket option for IPv4
+ sockets and the IPV6_MULTICAST_IF socket option for IPv6 sockets. The
+ socket must be in BoundState, otherwise this function does nothing.
+
+ \sa multicastInterface(), joinMulticastGroup(), leaveMulticastGroup()
+*/
+void QUdpSocket::setMulticastInterface(const QNetworkInterface &iface)
+{
+ Q_D(QUdpSocket);
+ if (!isValid()) {
+ qWarning("QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ return;
+ }
+ d->socketEngine->setMulticastInterface(iface);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
+/*!
+ Returns true if at least one datagram is waiting to be read;
+ otherwise returns false.
+
+ \sa pendingDatagramSize(), readDatagram()
+*/
+bool QUdpSocket::hasPendingDatagrams() const
+{
+ QT_CHECK_BOUND("QUdpSocket::hasPendingDatagrams()", false);
+ return d_func()->socketEngine->hasPendingDatagrams();
+}
+
+/*!
+ Returns the size of the first pending UDP datagram. If there is
+ no datagram available, this function returns -1.
+
+ \sa hasPendingDatagrams(), readDatagram()
+*/
+qint64 QUdpSocket::pendingDatagramSize() const
+{
+ QT_CHECK_BOUND("QUdpSocket::pendingDatagramSize()", -1);
+ return d_func()->socketEngine->pendingDatagramSize();
+}
+
+/*!
+ Sends the datagram at \a data of size \a size to the host
+ address \a address at port \a port. Returns the number of
+ bytes sent on success; otherwise returns -1.
+
+ Datagrams are always written as one block. The maximum size of a
+ datagram is highly platform-dependent, but can be as low as 8192
+ bytes. If the datagram is too large, this function will return -1
+ and error() will return DatagramTooLargeError.
+
+ Sending datagrams larger than 512 bytes is in general disadvised,
+ as even if they are sent successfully, they are likely to be
+ fragmented by the IP layer before arriving at their final
+ destination.
+
+ \warning In S60 5.0 and earlier versions, the writeDatagram return
+ value is not reliable for large datagrams.
+
+ \warning Calling this function on a connected UDP socket may
+ result in an error and no packet being sent. If you are using a
+ connected socket, use write() to send datagrams.
+
+ \sa readDatagram(), write()
+*/
+qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address,
+ quint16 port)
+{
+ Q_D(QUdpSocket);
+#if defined QUDPSOCKET_DEBUG
+ qDebug("QUdpSocket::writeDatagram(%p, %llu, \"%s\", %i)", data, size,
+ address.toString().toLatin1().constData(), port);
+#endif
+ if (!d->ensureInitialized(address))
+ return -1;
+
+ qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
+ d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
+
+ if (sent >= 0) {
+ emit bytesWritten(sent);
+ } else {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ emit error(d->socketError);
+ }
+ return sent;
+}
+
+/*!
+ \fn qint64 QUdpSocket::writeDatagram(const QByteArray &datagram,
+ const QHostAddress &host, quint16 port)
+ \overload
+
+ Sends the datagram \a datagram to the host address \a host and at
+ port \a port.
+*/
+
+/*!
+ Receives a datagram no larger than \a maxSize bytes and stores
+ it in \a data. The sender's host address and port is stored in
+ *\a address and *\a port (unless the pointers are 0).
+
+ Returns the size of the datagram on success; otherwise returns
+ -1.
+
+ If \a maxSize is too small, the rest of the datagram will be
+ lost. To avoid loss of data, call pendingDatagramSize() to
+ determine the size of the pending datagram before attempting to
+ read it. If \a maxSize is 0, the datagram will be discarded.
+
+ \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
+*/
+qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
+ quint16 *port)
+{
+ Q_D(QUdpSocket);
+
+#if defined QUDPSOCKET_DEBUG
+ qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
+#endif
+ QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
+ qint64 readBytes = d->socketEngine->readDatagram(data, maxSize, address, port);
+ d_func()->socketEngine->setReadNotificationEnabled(true);
+ if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ emit error(d->socketError);
+ }
+ return readBytes;
+}
+#endif // QT_NO_UDPSOCKET
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h
new file mode 100644
index 0000000000..7502349c7a
--- /dev/null
+++ b/src/network/socket/qudpsocket.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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 QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QUDPSOCKET_H
+#define QUDPSOCKET_H
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qhostaddress.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_UDPSOCKET
+
+class QNetworkInterface;
+class QUdpSocketPrivate;
+
+class Q_NETWORK_EXPORT QUdpSocket : public QAbstractSocket
+{
+ Q_OBJECT
+public:
+ enum BindFlag {
+ DefaultForPlatform = 0x0,
+ ShareAddress = 0x1,
+ DontShareAddress = 0x2,
+ ReuseAddressHint = 0x4
+ };
+ Q_DECLARE_FLAGS(BindMode, BindFlag)
+
+ explicit QUdpSocket(QObject *parent = 0);
+ virtual ~QUdpSocket();
+
+ bool bind(const QHostAddress &address, quint16 port);
+ bool bind(quint16 port = 0);
+ bool bind(const QHostAddress &address, quint16 port, BindMode mode);
+ bool bind(quint16 port, BindMode mode);
+ // ### Qt 5: Merge the bind functions
+
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress);
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+
+ QNetworkInterface multicastInterface() const;
+ void setMulticastInterface(const QNetworkInterface &iface);
+#endif
+
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+ qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = 0, quint16 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
+ inline qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
+ { return writeDatagram(datagram.constData(), datagram.size(), host, port); }
+
+private:
+ Q_DISABLE_COPY(QUdpSocket)
+ Q_DECLARE_PRIVATE(QUdpSocket)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QUdpSocket::BindMode)
+
+#endif // QT_NO_UDPSOCKET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QUDPSOCKET_H
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
new file mode 100644
index 0000000000..ac9001247a
--- /dev/null
+++ b/src/network/socket/socket.pri
@@ -0,0 +1,70 @@
+# Qt network socket
+
+HEADERS += socket/qabstractsocketengine_p.h \
+ socket/qhttpsocketengine_p.h \
+ socket/qsocks5socketengine_p.h \
+ socket/qabstractsocket.h \
+ socket/qabstractsocket_p.h \
+ socket/qtcpsocket.h \
+ socket/qudpsocket.h \
+ socket/qtcpserver.h \
+ socket/qlocalserver.h \
+ socket/qlocalserver_p.h \
+ socket/qlocalsocket.h \
+ socket/qlocalsocket_p.h
+
+SOURCES += socket/qabstractsocketengine.cpp \
+ socket/qhttpsocketengine.cpp \
+ socket/qsocks5socketengine.cpp \
+ socket/qabstractsocket.cpp \
+ socket/qtcpsocket.cpp \
+ socket/qudpsocket.cpp \
+ socket/qtcpserver.cpp \
+ socket/qlocalsocket.cpp \
+ socket/qlocalserver.cpp
+
+# On Symbian we use QSymbianSocketEngine
+symbian:SOURCES += socket/qsymbiansocketengine.cpp
+symbian:HEADERS += socket/qsymbiansocketengine_p.h
+# On others we use QNativeSocketEngine
+!symbian:SOURCES += socket/qnativesocketengine.cpp
+!symbian:HEADERS += socket/qnativesocketengine_p.h
+
+unix:!symbian: {
+ SOURCES += socket/qnativesocketengine_unix.cpp \
+ socket/qlocalsocket_unix.cpp \
+ socket/qlocalserver_unix.cpp
+}
+
+symbian: {
+ SOURCES += socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}
+
+unix:HEADERS += \
+ socket/qnet_unix_p.h
+
+win32:SOURCES += socket/qnativesocketengine_win.cpp \
+ socket/qlocalsocket_win.cpp \
+ socket/qlocalserver_win.cpp
+
+wince*: {
+ SOURCES -= socket/qlocalsocket_win.cpp \
+ socket/qlocalserver_win.cpp
+ SOURCES += socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}
+
+integrity: {
+ SOURCES -= socket/qlocalsocket_unix.cpp \
+ socket/qlocalserver_unix.cpp
+ SOURCES += socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp \
+ socket/qnativesocketengine_unix.cpp
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}