summaryrefslogtreecommitdiff
path: root/src/network/socket
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qabstractsocket.cpp2631
-rw-r--r--src/network/socket/qabstractsocket.h248
-rw-r--r--src/network/socket/qabstractsocket_p.h163
-rw-r--r--src/network/socket/qabstractsocketengine.cpp254
-rw-r--r--src/network/socket/qabstractsocketengine_p.h217
-rw-r--r--src/network/socket/qhttpsocketengine.cpp773
-rw-r--r--src/network/socket/qhttpsocketengine_p.h188
-rw-r--r--src/network/socket/qlocalserver.cpp395
-rw-r--r--src/network/socket/qlocalserver.h107
-rw-r--r--src/network/socket/qlocalserver_p.h165
-rw-r--r--src/network/socket/qlocalserver_tcp.cpp129
-rw-r--r--src/network/socket/qlocalserver_unix.cpp251
-rw-r--r--src/network/socket/qlocalserver_win.cpp252
-rw-r--r--src/network/socket/qlocalsocket.cpp504
-rw-r--r--src/network/socket/qlocalsocket.h157
-rw-r--r--src/network/socket/qlocalsocket_p.h212
-rw-r--r--src/network/socket/qlocalsocket_tcp.cpp437
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp566
-rw-r--r--src/network/socket/qlocalsocket_win.cpp537
-rw-r--r--src/network/socket/qnativesocketengine.cpp1140
-rw-r--r--src/network/socket/qnativesocketengine_p.h250
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp949
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp1211
-rw-r--r--src/network/socket/qsocks5socketengine.cpp1850
-rw-r--r--src/network/socket/qsocks5socketengine_p.h288
-rw-r--r--src/network/socket/qtcpserver.cpp643
-rw-r--r--src/network/socket/qtcpserver.h109
-rw-r--r--src/network/socket/qtcpsocket.cpp114
-rw-r--r--src/network/socket/qtcpsocket.h74
-rw-r--r--src/network/socket/qtcpsocket_p.h68
-rw-r--r--src/network/socket/qudpsocket.cpp424
-rw-r--r--src/network/socket/qudpsocket.h99
-rw-r--r--src/network/socket/socket.pri46
33 files changed, 15451 insertions, 0 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
new file mode 100644
index 0000000000..910e30aee9
--- /dev/null
+++ b/src/network/socket/qabstractsocket.cpp
@@ -0,0 +1,2631 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 io
+ \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.
+
+ 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, QHttp, QTcpServer
+*/
+
+/*!
+ \fn void QAbstractSocket::hostFound()
+
+ This signal is emitted after connectToHost() has been called and
+ the host lookup has succeeded.
+
+ \sa connected()
+*/
+
+/*!
+ \fn void QAbstractSocket::connected()
+
+ This signal is emitted after connectToHost() has been called and
+ a connection has been successfully established.
+
+ \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_REGISTER_METATYPE.
+
+ \sa error(), errorString()
+*/
+
+/*!
+ \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.
+
+ \sa state()
+*/
+
+/*!
+ \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()
+*/
+
+#include "qabstractsocket.h"
+#include "qabstractsocket_p.h"
+
+#include <qabstracteventdispatcher.h>
+#include <qdatetime.h>
+#include <qhostaddress.h>
+#include <qhostinfo.h>
+#include <qmetaobject.h>
+#include <qpointer.h>
+#include <qtimer.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),
+ connectTimeElapsed(0),
+ hostLookupId(-1),
+ 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();
+ }
+}
+
+/*! \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 = "TcpSocket";
+ else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = "UdpSocket";
+ else typeStr = "UnknownSocketType";
+ QString protocolStr;
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol";
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol";
+ else protocolStr = "UnknownNetworkLayerProtocol";
+#endif
+
+ resetSocketLayer();
+ socketEngine = QAbstractSocketEngine::createSocketEngine(q->socketType(), proxyInUse, q);
+ 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);
+ }
+ }
+ 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
+ readSocketNotifierCalled = false;
+ 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();
+ readSocketNotifierCalled = false;
+ 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 && socketEngine && socketEngine->hasPendingDatagrams())
+#endif
+ ;
+
+ if (!emittedReadyRead && hasData) {
+ emittedReadyRead = true;
+ emit q->readyRead();
+ emittedReadyRead = false;
+ }
+
+ // 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
+ readSocketNotifierCalled = false;
+ 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;
+ }
+ readSocketNotifierCalled = 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->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()) {
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocketPrivate::flush() nothing to do: valid ? %s, writeBuffer.isEmpty() ? %s",
+ socketEngine->isValid() ? "yes" : "no", writeBuffer.isEmpty() ? "yes" : "no");
+#endif
+ 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());
+ emit q->error(socketError);
+ // an unexpected error so close the socket.
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug() << "QAbstractSocketPrivate::flush() write error, aborting." << socketEngine->errorString();
+#endif
+ 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) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(written);
+ emittedBytesWritten = false;
+ }
+ }
+
+ if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled())
+ 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;
+
+ addresses = hostInfo.addresses();
+
+#if defined(QABSTRACTSOCKET_DEBUG)
+ QString s = "{";
+ for (int i = 0; i < addresses.count(); ++i) {
+ if (i != 0) s += ", ";
+ s += addresses.at(i).toString();
+ }
+ s += "}";
+ 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();
+ }
+}
+
+/*! \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();
+#ifdef Q_OS_LINUX
+ if (bytesToRead > 0) // ### See setSocketDescriptor()
+ bytesToRead += addToBytesAvailable;
+#endif
+ 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 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
+}
+
+/*! \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.,
+ "qtsoftware.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) {
+ qWarning("QAbstractSocket::connectToHost() called when already 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;
+#ifdef Q_OS_LINUX
+ // ### See setSocketDescriptor().
+ d->addToBytesAvailable = 0;
+#endif
+ 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 (!d_func()->isBuffered)
+ openMode |= QAbstractSocket::Unbuffered;
+ 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)
+ d->hostLookupId = QHostInfo::lookupHost(hostName, this, SLOT(_q_startConnecting(QHostInfo)));
+ }
+
+#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();
+ if (d->isBuffered)
+ available += (qint64) d->readBuffer.size();
+ else if (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);
+ 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;
+
+#ifdef Q_OS_LINUX
+ // ### This is a workaround for certain broken Linux kernels, when using
+ // QTcpSocket with a Unix domain socket. It was introduced around 2.6.9,
+ // and fixed at some point after that.
+ // http://archive.linux-usenet.com/index-t-73300.html
+ // We can provide a better workaround for this: readFromSocket() can loop
+ // while reading, but this must happen without triggering an implicit
+ // close because of reading after the socket has closed.
+ d->addToBytesAvailable = 4096;
+#endif
+
+ return true;
+}
+
+/*
+ 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.
+
+ \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;
+ QTime 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;
+ d->_q_startConnecting(QHostInfo::fromName(d->hostName));
+ }
+ if (state() == UnconnectedState)
+ return false;
+
+ 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 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 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;
+ }
+
+ QTime 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;
+
+ QTime 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;
+ }
+
+ QTime 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);
+ if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ if (!d->isBuffered) {
+ if (!d->socketEngine)
+ return -1; // no socket engine is probably EOF
+ qint64 readBytes = d->socketEngine->read(data, maxSize);
+ if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ }
+ if (!d->socketEngine->isReadNotificationEnabled())
+ d->socketEngine->setReadNotificationEnabled(true);
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
+ data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
+ readBytes);
+#endif
+ return readBytes;
+ }
+
+ if (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);
+
+ // If readFromSocket() read data, copy it to its destination.
+ if (maxSize == 1) {
+ *data = d->readBuffer.getChar();
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data);
+#endif
+ return 1;
+ }
+
+ 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 defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
+ 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) {
+ 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;
+ }
+
+ 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;
+}
+
+/*!
+ Disconnects the socket's connection with the host.
+
+ \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
+ } 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->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 || 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->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..1b86e92ce2
--- /dev/null
+++ b/src/network/socket/qabstractsocket.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+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
+ };
+
+ 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);
+
+ 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())
+
+#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..4cb7dcb932
--- /dev/null
+++ b/src/network/socket/qabstractsocket_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 QLibrary 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/qnativesocketengine_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();
+
+ 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();
+
+#ifdef Q_OS_LINUX
+ qint64 addToBytesAvailable;
+#endif
+ qint64 readBufferMaxSize;
+ QRingBuffer readBuffer;
+ QRingBuffer writeBuffer;
+
+ bool isBuffered;
+ int blockingTimeout;
+
+ QTimer *connectTimer;
+ int connectTimeElapsed;
+
+ int hostLookupId;
+
+ QAbstractSocket::SocketType socketType;
+ QAbstractSocket::SocketState state;
+
+ QAbstractSocket::SocketError socketError;
+};
+
+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..620cf8ba84
--- /dev/null
+++ b/src/network/socket/qabstractsocketengine.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractsocketengine_p.h"
+#include "qnativesocketengine_p.h"
+#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
+
+ return new QNativeSocketEngine(parent);
+}
+
+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;
+ }
+ return new QNativeSocketEngine(parent);
+}
+
+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..6bfa456d1f
--- /dev/null
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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;
+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
+ };
+
+ 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
+ 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
+
+ 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..540c443e2f
--- /dev/null
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -0,0 +1,773 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhttpsocketengine_p.h"
+#include "qtcpsocket.h"
+#include "qhostaddress.h"
+#include "qdatetime.h"
+#include "qurl.h"
+#include "qhttp.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);
+
+ // 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 = 0;
+
+ if (!d->readBuffer.isEmpty()) {
+ // Read as much from the buffer as we can.
+ bytesRead = qMin((qint64)d->readBuffer.size(), maxlen);
+ memcpy(data, d->readBuffer.constData(), bytesRead);
+ data += bytesRead;
+ maxlen -= bytesRead;
+ d->readBuffer = d->readBuffer.mid(bytesRead);
+ }
+
+ qint64 bytesReadFromSocket = d->socket->read(data, maxlen);
+
+ if (d->socket->state() == QAbstractSocket::UnconnectedState
+ && d->socket->bytesAvailable() == 0) {
+ emitReadNotification();
+ }
+
+ if (bytesReadFromSocket > 0) {
+ // Add to what we read so far.
+ bytesRead += bytesReadFromSocket;
+ } else if (bytesRead == 0 && bytesReadFromSocket == -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
+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
+
+int QHttpSocketEngine::option(SocketOption) const
+{
+ return -1;
+}
+
+bool QHttpSocketEngine::setOption(SocketOption, int)
+{
+ 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;
+
+ QTime 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;
+ }
+
+ QTime 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"
+ "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();
+
+ 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) {
+ emitReadNotification();
+ } else {
+ qDebug() << "QHttpSocketEngine::slotSocketError: got weird error =" << error;
+ }
+}
+
+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 (d->readNotificationEnabled && !d->readNotificationPending) {
+ 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)
+{
+ 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;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
new file mode 100644
index 0000000000..d0c53d000a
--- /dev/null
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+ 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
+
+ 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;
+ 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..d6b1507d3d
--- /dev/null
+++ b/src/network/socket/qlocalserver.cpp
@@ -0,0 +1,395 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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.
+
+ Note that this feature is not supported on Windows 9x.
+
+ \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 = QString();
+ d->fullServerName = QString();
+ d->errorString = QString();
+ 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 = QString();
+ d->fullServerName = QString();
+ 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 Q_OS_WIN
+ d->socketNotifier->setEnabled(d->pendingConnections.size()
+ <= d->maxPendingConnections);
+#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..8e8babdab8
--- /dev/null
+++ b/src/network/socket/qlocalserver.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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)
+#if defined(QT_LOCALSOCKET_TCP)
+ Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection())
+#elif defined(Q_OS_WIN)
+ Q_PRIVATE_SLOT(d_func(), void _q_openSocket(HANDLE handle))
+ Q_PRIVATE_SLOT(d_func(), void _q_stoppedListening())
+ Q_PRIVATE_SLOT(d_func(), void _q_setError(QAbstractSocket::SocketError error, const QString &errorString))
+#else
+ Q_PRIVATE_SLOT(d_func(), void _q_socketActivated())
+#endif
+};
+
+#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..8e96401347
--- /dev/null
+++ b/src/network/socket/qlocalserver_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <qthread.h>
+#else
+# include <private/qnativesocketengine_p.h>
+# include <qsocketnotifier.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+
+/*!
+ \internal
+ QLocalServerThread exists because Windows does not have a
+ way to provide notifications when there is a new connections to
+ the server.
+ */
+class QLocalServerThread : public QThread
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void connected(HANDLE newSocket);
+ void error(QAbstractSocket::SocketError error, const QString &errorString);
+
+public:
+ QLocalServerThread(QObject *parent = 0);
+ ~QLocalServerThread();
+ void closeServer();
+
+public:
+ QString setName(const QString &name);
+ void run();
+ void stop();
+ bool makeHandle();
+
+ HANDLE gotConnectionEvent;
+ QQueue<HANDLE> pendingHandles;
+ int maxPendingConnections;
+private:
+ HANDLE stopEvent;
+ QString fullServerName;
+};
+
+#endif
+
+class QLocalServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QLocalServer)
+
+public:
+ QLocalServerPrivate() :
+#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+ inWaitingFunction(false),
+#elif !defined(QT_LOCALSOCKET_TCP)
+ 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);
+
+#if defined(QT_LOCALSOCKET_TCP)
+ void _q_onNewConnection();
+
+ QTcpServer tcpServer;
+ QMap<quintptr, QTcpSocket*> socketMap;
+#elif defined(Q_OS_WIN)
+ void _q_openSocket(HANDLE socket);
+ void _q_stoppedListening();
+ void _q_setError(QAbstractSocket::SocketError error, const QString &errorString);
+
+ QLocalServerThread waitForConnection;
+ bool inWaitingFunction;
+#else
+ void setError(const QString &function);
+ void _q_socketActivated();
+
+ 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..f85777b830
--- /dev/null
+++ b/src/network/socket/qlocalserver_tcp.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+ *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..065a9de5b0
--- /dev/null
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+
+#ifndef QT_NO_LOCALSERVER
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <qdebug.h>
+#include <qdir.h>
+#include <qdatetime.h>
+
+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 = qSocket(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);
+
+ // bind
+ if(-1 == qBind(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 == qListen(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_socketActivated()));
+ socketNotifier->setEnabled(maxPendingConnections > 0);
+ return true;
+}
+
+/*!
+ \internal
+
+ \sa QLocalServer::closeServer()
+ */
+void QLocalServerPrivate::closeServer()
+{
+ if (-1 != listenSocket)
+ QT_CLOSE(listenSocket);
+ listenSocket = -1;
+
+ if (socketNotifier)
+ 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_socketActivated()
+{
+ Q_Q(QLocalServer);
+ if (-1 == listenSocket)
+ return;
+
+ ::sockaddr_un addr;
+ QT_SOCKLEN_T length = sizeof(sockaddr_un);
+ int connectedSocket = qAccept(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;
+
+ // 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.
+ QTime timer;
+ timer.start();
+ while (pendingConnections.isEmpty() && (-1 == msec || timer.elapsed() < msec)) {
+ result = ::select(listenSocket + 1, &readfds, 0, 0, &timeout);
+ if (-1 == result && errno != EINTR) {
+ setError(QLatin1String("QLocalServer::waitForNewConnection"));
+ closeServer();
+ break;
+ }
+ if (result > 0)
+ _q_socketActivated();
+ }
+ 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..880cd7ea21
--- /dev/null
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalserver.h"
+#include "qlocalserver_p.h"
+#include "qlocalsocket.h"
+
+#include <qdebug.h>
+#include <qdatetime.h>
+#include <qcoreapplication.h>
+#include <QMetaType>
+
+// 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
+
+QT_BEGIN_NAMESPACE
+
+QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent),
+ maxPendingConnections(1)
+{
+ stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+QLocalServerThread::~QLocalServerThread()
+{
+ stop();
+ closeServer();
+ CloseHandle(stopEvent);
+ CloseHandle(gotConnectionEvent);
+}
+
+void QLocalServerThread::stop()
+{
+ if (isRunning()) {
+ SetEvent(stopEvent);
+ wait();
+ ResetEvent(stopEvent);
+ }
+}
+
+void QLocalServerThread::closeServer()
+{
+ while (!pendingHandles.isEmpty())
+ CloseHandle(pendingHandles.dequeue());
+}
+
+QString QLocalServerThread::setName(const QString &name)
+{
+ QString pipePath = QLatin1String("\\\\.\\pipe\\");
+ if (name.startsWith(pipePath))
+ fullServerName = name;
+ else
+ fullServerName = pipePath + name;
+ for (int i = pendingHandles.count(); i < maxPendingConnections; ++i)
+ if (!makeHandle())
+ break;
+ return fullServerName;
+}
+
+bool QLocalServerThread::makeHandle()
+{
+ if (pendingHandles.count() >= maxPendingConnections)
+ return false;
+
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ QT_WA({
+ handle = CreateNamedPipeW(
+ (TCHAR*)fullServerName.utf16(), // pipe name
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
+ PIPE_TYPE_MESSAGE | // message type pipe
+ PIPE_READMODE_MESSAGE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ BUFSIZE, // output buffer size
+ BUFSIZE, // input buffer size
+ 3000, // client time-out
+ NULL);
+ }, {
+ handle = CreateNamedPipeA(
+ fullServerName.toLocal8Bit().constData(), // pipe name
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
+ PIPE_TYPE_MESSAGE | // message type pipe
+ PIPE_READMODE_MESSAGE | // message-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 (INVALID_HANDLE_VALUE == handle) {
+ return false;
+ }
+ pendingHandles.enqueue(handle);
+ return true;
+}
+
+void QLocalServerThread::run()
+{
+ OVERLAPPED op;
+ HANDLE handleArray[2];
+ memset(&op, 0, sizeof(op));
+ handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ handleArray[1] = stopEvent;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+
+ forever {
+ if (INVALID_HANDLE_VALUE == handle) {
+ makeHandle();
+ if (!pendingHandles.isEmpty())
+ handle = pendingHandles.dequeue();
+ }
+ if (INVALID_HANDLE_VALUE == handle) {
+ int windowsError = GetLastError();
+ QString function = QLatin1String("QLocalServer::run");
+ QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError);
+ emit error(QAbstractSocket::UnknownSocketError, errorString);
+ CloseHandle(handleArray[0]);
+ SetEvent(gotConnectionEvent);
+ return;
+ }
+
+ BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+ if (!isConnected) {
+ switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE))
+ {
+ case WAIT_OBJECT_0 + 1:
+ CloseHandle(handle);
+ CloseHandle(handleArray[0]);
+ return;
+ }
+ }
+ emit connected(handle);
+ handle = INVALID_HANDLE_VALUE;
+ ResetEvent(handleArray[0]);
+ SetEvent(gotConnectionEvent);
+ }
+}
+
+void QLocalServerPrivate::init()
+{
+ Q_Q(QLocalServer);
+ qRegisterMetaType<HANDLE>("HANDLE");
+ q->connect(&waitForConnection, SIGNAL(connected(HANDLE)),
+ q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection);
+ q->connect(&waitForConnection, SIGNAL(finished()),
+ q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
+ q->connect(&waitForConnection, SIGNAL(terminated()),
+ q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
+ q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)),
+ q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &)));
+}
+
+bool QLocalServerPrivate::removeServer(const QString &name)
+{
+ Q_UNUSED(name);
+ return true;
+}
+
+bool QLocalServerPrivate::listen(const QString &name)
+{
+ fullServerName = waitForConnection.setName(name);
+ serverName = name;
+ waitForConnection.start();
+ return true;
+}
+
+void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString)
+{
+ error = e;
+ errorString = eString;
+}
+
+void QLocalServerPrivate::_q_stoppedListening()
+{
+ Q_Q(QLocalServer);
+ if (!inWaitingFunction)
+ q->close();
+}
+
+void QLocalServerPrivate::_q_openSocket(HANDLE handle)
+{
+ Q_Q(QLocalServer);
+ q->incomingConnection((int)handle);
+}
+
+void QLocalServerPrivate::closeServer()
+{
+ waitForConnection.stop();
+ waitForConnection.closeServer();
+}
+
+void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
+{
+ Q_Q(QLocalServer);
+ if (!pendingConnections.isEmpty() || !q->isListening())
+ return;
+
+ DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent,
+ (msecs == -1) ? INFINITE : msecs);
+ if (result == WAIT_TIMEOUT) {
+ if (timedOut)
+ *timedOut = true;
+ } else {
+ ResetEvent(waitForConnection.gotConnectionEvent);
+ QCoreApplication::instance()->processEvents();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp
new file mode 100644
index 0000000000..327bfc6341
--- /dev/null
+++ b/src/network/socket/qlocalsocket.cpp
@@ -0,0 +1,504 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 Window 9x.
+
+ \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()
+*/
+
+/*!
+ \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 msec)
+
+ Waits until the socket is connected, up to \a msec 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 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 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.
+
+ \sa error(), errorString()
+*/
+
+/*!
+ \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.
+
+ \sa state()
+*/
+
+/*!
+ 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();
+#ifndef Q_OS_WIN
+ 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: This 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..b8ad5c7294
--- /dev/null
+++ b/src/network/socket/qlocalsocket.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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())
+#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..dd48d0ab6b
--- /dev/null
+++ b/src/network/socket/qlocalsocket_p.h
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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"
+#else
+# include "private/qnativesocketengine_p.h"
+# include <qtcpsocket.h>
+# include <qsocketnotifier.h>
+# include <errno.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+static inline int qSocket(int af, int socketype, int proto)
+{
+ int ret;
+ while((ret = qt_socket_socket(af, socketype, proto)) == -1 && errno == EINTR){}
+ return ret;
+}
+
+static inline int qBind(int fd, const sockaddr *sa, int len)
+{
+ int ret;
+ while((ret = QT_SOCKET_BIND(fd, (sockaddr*)sa, len)) == -1 && errno == EINTR){}
+ return ret;
+}
+
+static inline int qConnect(int fd, const sockaddr *sa, int len)
+{
+ int ret;
+ while((ret = QT_SOCKET_CONNECT(fd, (sockaddr*)sa, len)) == -1 && errno == EINTR){}
+ return ret;
+}
+
+static inline int qListen(int fd, int backlog)
+{
+ int ret;
+ while((ret = qt_socket_listen(fd, backlog)) == -1 && errno == EINTR){}
+ return ret;
+}
+
+static inline int qAccept(int fd, struct sockaddr *addr, QT_SOCKLEN_T *addrlen)
+{
+ int ret;
+ while((ret = qt_socket_accept(fd, addr, addrlen)) == -1 && errno == EINTR){}
+ return ret;
+}
+#endif //#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+
+#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() {
+ CloseHandle(overlapped.hEvent);
+ }
+
+ void setErrorString(const QString &function);
+ void _q_notified();
+ void _q_canWrite();
+ void _q_pipeClosed();
+ qint64 readData(char *data, qint64 maxSize);
+ qint64 bytesAvailable();
+ bool readFromSocket();
+ HANDLE handle;
+ OVERLAPPED overlapped;
+ QWindowsPipeWriter *pipeWriter;
+ qint64 readBufferMaxSize;
+ QRingBuffer readBuffer;
+ QTimer dataNotifier;
+ QLocalSocket::LocalSocketError error;
+ bool readyReadEmitted;
+ bool pipeClosed;
+#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();
+ 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..a4c6aa9aff
--- /dev/null
+++ b/src/network/socket/qlocalsocket_tcp.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 = QString();
+ fullServerName = QString();
+ 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 = QString();
+ 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 = QString();
+ d->fullServerName = QString();
+ 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..a375e9ba10
--- /dev/null
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -0,0 +1,566 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket.h"
+#include "qlocalsocket_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 <qdatetime.h>
+#include <qdir.h>
+#include <qdebug.h>
+
+#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 = QString();
+ fullServerName = QString();
+ 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 = QString();
+ 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 = qSocket(PF_UNIX, SOCK_STREAM, 0))) {
+ d->errorOccurred(UnsupportedSocketOperationError,
+ QLatin1String("QLocalSocket::connectToServer"));
+ return;
+ }
+
+ // 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;
+ }
+
+ // _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 == qConnect(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->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!
+ if (delayConnect) {
+ delayConnect->setEnabled(false);
+ delete delayConnect;
+ delayConnect = 0;
+ }
+ 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 = QString();
+ 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();
+}
+
+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();
+ if (d->delayConnect) {
+ d->delayConnect->setEnabled(false);
+ delete d->delayConnect;
+ d->delayConnect = 0;
+ d->connectTimer->stop();
+ delete d->connectTimer;
+ d->connectTimer = 0;
+ }
+ if (d->connectingSocket != -1)
+ ::close(d->connectingSocket);
+ d->connectingSocket = -1;
+ d->connectingName = QString();
+ d->connectingOpenMode = 0;
+ d->serverName = QString();
+ d->fullServerName = QString();
+ 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 readfds;
+ FD_ZERO(&readfds);
+ FD_SET(d->connectingSocket, &readfds);
+
+ 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.
+ QTime timer;
+ timer.start();
+ while (state() == ConnectingState
+ && (-1 == msec || timer.elapsed() < msec)) {
+ result = ::select(d->connectingSocket + 1, &readfds, 0, 0, &timeout);
+ 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..e759d0bd1b
--- /dev/null
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -0,0 +1,537 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocalsocket.h"
+#include "qlocalsocket_p.h"
+
+#include <private/qthread_p.h>
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#define NOTIFYTIMEOUT 100
+
+void QLocalSocketPrivate::init()
+{
+ Q_Q(QLocalSocket);
+ QObject::connect(&dataNotifier, SIGNAL(timeout()), q, SLOT(_q_notified()));
+ overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+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;
+ 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),
+ error(QLocalSocket::UnknownSocketError),
+ readyReadEmitted(false),
+ pipeClosed(false),
+ state(QLocalSocket::UnconnectedState)
+{
+}
+
+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;
+ QT_WA({
+ localSocket = CreateFileW(
+ (TCHAR*)d->fullServerName.utf16(), // pipe name
+ permissions,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ 0, // default attributes
+ NULL); // no template file
+ }, {
+ localSocket = CreateFileA(
+ d->fullServerName.toLocal8Bit().constData(), // pipe name
+ permissions,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ 0, // default attributes
+ 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.
+ QT_WA({
+ if (!WaitNamedPipeW((TCHAR*)d->fullServerName.utf16(), 5000))
+ break;
+ }, {
+ if (!WaitNamedPipeA(d->fullServerName.toLocal8Bit().constData(), 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), openMode) {
+ d->handle = localSocket;
+ emit connected();
+ }
+}
+
+// This is reading from the buffer
+qint64 QLocalSocket::readData(char *data, qint64 maxSize)
+{
+ Q_D(QLocalSocket);
+ if (d->readBuffer.isEmpty()) {
+ if (!d->readFromSocket()) {
+ if (d->pipeClosed)
+ return -1;
+ return 0;
+ }
+ }
+
+ if (!d->dataNotifier.isActive() && d->threadData->eventDispatcher)
+ d->dataNotifier.start(NOTIFYTIMEOUT);
+
+ if (d->readBuffer.isEmpty())
+ return qint64(0);
+
+ // If readFromSocket() read data, copy it to its destination.
+ if (maxSize == 1) {
+ *data = d->readBuffer.getChar();
+ return 1;
+ }
+
+ 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);
+ }
+ return readSoFar;
+}
+
+/*!
+ \internal
+ read from the socket
+ */
+qint64 QLocalSocketPrivate::readData(char *data, qint64 maxSize)
+{
+ DWORD bytesRead = 0;
+ overlapped.Offset = 0;
+ overlapped.OffsetHigh = 0;
+ bool success = ReadFile(handle, data, maxSize, &bytesRead, &overlapped);
+ if (!success && GetLastError() == ERROR_IO_PENDING)
+ if (GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE))
+ success = true;
+ if (!success) {
+ setErrorString(QLatin1String("QLocalSocket::readData"));
+ return 0;
+ }
+ return bytesRead;
+}
+
+/*!
+ \internal
+ Reads data from the socket into the readbuffer
+ */
+bool QLocalSocketPrivate::readFromSocket()
+{
+ qint64 bytesToRead = bytesAvailable();
+ if (bytesToRead == 0)
+ return false;
+
+ if (readBufferMaxSize && bytesToRead
+ > (readBufferMaxSize - readBuffer.size()))
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+
+ char *ptr = readBuffer.reserve(bytesToRead);
+ qint64 readBytes = readData(ptr, bytesToRead);
+ if (readBytes == 0) {
+ readBuffer.chop(bytesToRead);
+ return false;
+ }
+ readyReadEmitted = false;
+ readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+ return true;
+}
+
+qint64 QLocalSocket::writeData(const char *data, qint64 maxSize)
+{
+ Q_D(QLocalSocket);
+ if (!d->pipeWriter) {
+ d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
+ d->pipeWriter->start();
+ connect(d->pipeWriter, SIGNAL(canWrite()), this, SLOT(_q_canWrite()));
+ }
+ return d->pipeWriter->write(data, maxSize);
+}
+
+void QLocalSocket::abort()
+{
+ close();
+}
+
+/*!
+ The number of bytes available from the pipe
+ */
+qint64 QLocalSocketPrivate::bytesAvailable()
+{
+ Q_Q(QLocalSocket);
+ if (q->state() != QLocalSocket::ConnectedState)
+ return 0;
+ DWORD bytes;
+ if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) {
+ return bytes;
+ } else {
+ if (ERROR_BROKEN_PIPE == GetLastError() && !pipeClosed) {
+ pipeClosed = true;
+ 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->readBuffer.size();
+ 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 (d->readBuffer.indexOf('\n') != -1 || QIODevice::canReadLine());
+}
+
+void QLocalSocket::close()
+{
+ Q_D(QLocalSocket);
+ if (state() == UnconnectedState)
+ return;
+
+ QIODevice::close();
+ d->state = ClosingState;
+ emit stateChanged(d->state);
+ d->readyReadEmitted = false;
+ emit readChannelFinished();
+ d->serverName = QString();
+ d->fullServerName = QString();
+
+ if (state() != UnconnectedState && bytesToWrite() > 0) {
+ disconnectFromServer();
+ return;
+ }
+ d->pipeClosed = false;
+ DisconnectNamedPipe(d->handle);
+ CloseHandle(d->handle);
+ d->handle = INVALID_HANDLE_VALUE;
+ d->state = UnconnectedState;
+ emit stateChanged(d->state);
+ emit disconnected();
+ if (d->pipeWriter) {
+ delete d->pipeWriter;
+ d->pipeWriter = 0;
+ }
+ d->dataNotifier.stop();
+}
+
+bool QLocalSocket::flush()
+{
+ Q_D(QLocalSocket);
+ if (d->pipeWriter)
+ return d->pipeWriter->waitForWrite(0);
+ return false;
+}
+
+void QLocalSocket::disconnectFromServer()
+{
+ Q_D(QLocalSocket);
+ 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();
+ QIODevice::open(openMode);
+ d->handle = (int*)socketDescriptor;
+ d->state = socketState;
+ emit stateChanged(d->state);
+ if (d->threadData->eventDispatcher)
+ d->dataNotifier.start(NOTIFYTIMEOUT);
+ return true;
+}
+
+void QLocalSocketPrivate::_q_canWrite()
+{
+ Q_Q(QLocalSocket);
+ if (state == QLocalSocket::ClosingState)
+ q->close();
+}
+
+void QLocalSocketPrivate::_q_notified()
+{
+ Q_Q(QLocalSocket);
+ if (0 != bytesAvailable()) {
+ if (readBufferMaxSize == 0 || readBuffer.size() < readBufferMaxSize) {
+ if (!readFromSocket()) {
+ return;
+ }
+ // wait until buffer is cleared before starting again
+ if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize) {
+ dataNotifier.stop();
+ }
+ }
+ if (!readyReadEmitted) {
+ readyReadEmitted = true;
+ q->emit 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;
+ QIncrementalSleepTimer timer(msecs);
+ forever {
+ d->_q_notified();
+ 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);
+ QIncrementalSleepTimer timer(msecs);
+ forever {
+ d->_q_notified();
+ if (bytesAvailable() > 0) {
+ if (!d->readyReadEmitted) {
+ d->readyReadEmitted = true;
+ emit readyRead();
+ }
+ return true;
+ }
+
+ Sleep(timer.nextSleepTime());
+ if (timer.hasTimedOut())
+ break;
+ }
+
+ return false;
+}
+
+bool QLocalSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(const QLocalSocket);
+ if (!d->pipeWriter)
+ return false;
+
+ QIncrementalSleepTimer timer(msecs);
+ forever {
+ if (d->pipeWriter->hadWritten())
+ return true;
+
+ if (d->pipeWriter->bytesToWrite() == 0)
+ 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.
+ if (d->pipeWriter->waitForWrite(0))
+ return true;
+
+ Sleep(timer.nextSleepTime());
+ if (timer.hasTimedOut())
+ break;
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
new file mode 100644
index 0000000000..b25b887c29
--- /dev/null
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -0,0 +1,1140 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+
+/*! \class QNativeSocketEngine
+ \internal
+
+ \brief The QNativeSocketEngine class provides low level access to a socket.
+
+ \reentrant
+ \ingroup io
+ \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 "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.
+ return;
+ }
+ if (error != QAbstractSocket::SocketError(11))
+ hasSetSocketError = true;
+
+ socketError = error;
+
+ switch (errorString) {
+ case NonBlockingInitFailedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to initialize non-blocking socket"));
+ break;
+ case BroadcastingInitFailedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to initialize broadcast socket"));
+ break;
+ case NoIpV6ErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Attempt to use IPv6 socket on a platform with no IPv6 support"));
+ break;
+ case RemoteHostClosedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The remote host closed the connection"));
+ break;
+ case TimeOutErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network operation timed out"));
+ break;
+ case ResourceErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Out of resources"));
+ break;
+ case OperationUnsupportedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unsupported socket operation"));
+ break;
+ case ProtocolUnsupportedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Protocol type not supported"));
+ break;
+ case InvalidSocketErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Invalid socket descriptor"));
+ break;
+ case HostUnreachableErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Host unreachable"));
+ break;
+ case NetworkUnreachableErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network unreachable"));
+ break;
+ case AccessErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Permission denied"));
+ break;
+ case ConnectionTimeOutErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Connection timed out"));
+ break;
+ case ConnectionRefusedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Connection refused"));
+ break;
+ case AddressInuseErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The bound address is already in use"));
+ break;
+ case AddressNotAvailableErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The address is not available"));
+ break;
+ case AddressProtectedErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The address is protected"));
+ break;
+ case DatagramTooLargeErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Datagram was too large to send"));
+ break;
+ case SendDatagramErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to send a message"));
+ break;
+ case ReceiveDatagramErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to receive a message"));
+ break;
+ case WriteErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to write"));
+ break;
+ case ReadErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network error"));
+ break;
+ case PortInuseErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Another socket is already listening on the same port"));
+ break;
+ case NotSocketErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Operation on non-socket"));
+ break;
+ case InvalidProxyTypeString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The proxy type is invalid for this operation"));
+ break;
+ case UnknownSocketErrorString:
+ socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "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");
+ }
+
+ // Set the send and receive buffer sizes to a magic size, found
+ // most optimal for our platforms.
+ 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();
+}
+
+/*!
+ 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);
+}
+
+/*!
+ 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;
+ }
+ 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);
+ 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(const 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;
+ }
+#endif
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+ 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(const 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;
+ }
+#endif
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ QNativeSocketEnginePrivate::TimeOutErrorString);
+ 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) {
+ 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..3366f2de9a
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef Q_OS_WIN
+// Almost always the same. If not, specify in qplatformdefs.h.
+#if !defined(QT_SOCKOPTLEN_T)
+# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
+#endif
+
+// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
+static inline int qt_socket_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen)
+{ return ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen)); }
+#if defined(accept)
+# undef accept
+#endif
+
+// UnixWare 7 redefines listen -> _listen
+static inline int qt_socket_listen(int s, int backlog)
+{ return ::listen(s, backlog); }
+#if defined(listen)
+# undef listen
+#endif
+
+// UnixWare 7 redefines socket -> _socket
+static inline int qt_socket_socket(int domain, int type, int protocol)
+{ return ::socket(domain, type, protocol); }
+#if defined(socket)
+# undef socket
+#endif
+
+#endif
+
+class QNativeSocketEnginePrivate;
+
+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();
+
+ 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 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();
+ 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..534f7ecf70
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -0,0 +1,949 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+
+#include "qnativesocketengine_p.h"
+#include "qiodevice.h"
+#include "qhostaddress.h"
+#include "qvarlengtharray.h"
+#include "qdatetime.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
+
+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()
+{
+ // 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);
+ }
+}
+
+/*
+ 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(struct sockaddr *sa, quint16 *port, QHostAddress *addr)
+{
+#if !defined(QT_NO_IPV6)
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ Q_IPV6ADDR tmp;
+ memcpy(&tmp, &sa6->sin6_addr.s6_addr, sizeof(tmp));
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(tmp);
+ *addr = tmpAddress;
+#ifndef QT_NO_IPV6IFNAME
+ char scopeid[IFNAMSIZ];
+ if (::if_indextoname(sa6->sin6_scope_id, scopeid) > 0) {
+ addr->setScopeId(QLatin1String(scopeid));
+ } else
+#endif
+ addr->setScopeId(QString::number(sa6->sin6_scope_id));
+ }
+ if (port)
+ *port = ntohs(sa6->sin6_port);
+ return;
+ }
+#endif
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+ if (port)
+ *port = ntohs(sa4->sin_port);
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(ntohl(sa4->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_socket_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;
+ }
+
+ // Ensure that the socket is closed on exec*().
+ ::fcntl(socket, F_SETFD, FD_CLOEXEC);
+ 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;
+ 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;
+ }
+
+ int v = -1;
+ QT_SOCKOPTLEN_T len = sizeof(v);
+ if (getsockopt(socketDescriptor, SOL_SOCKET, 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;
+ 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.
+ 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;
+ }
+
+ return true;
+ }
+ case QNativeSocketEngine::AddressReusable:
+#ifdef SO_REUSEPORT
+ n = SO_REUSEPORT;
+#else
+ n = SO_REUSEADDR;
+#endif
+ break;
+ case QNativeSocketEngine::BindExclusively:
+ return true;
+ case QNativeSocketEngine::ReceiveOutOfBandData:
+ n = SO_OOBINLINE;
+ break;
+ }
+
+ return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0;
+}
+
+bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, 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 (addr.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(addr.scopeId().toLatin1().data());
+#else
+ sockAddrIPv6.sin6_scope_id = addr.scopeId().toInt();
+#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_SOCKET_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_socket_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_socket_accept(socketDescriptor, 0, 0);
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
+#endif
+ // Ensure that the socket is closed on exec*()
+ ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
+ return acceptedDescriptor;
+}
+
+qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
+{
+ /*
+ Apparently, there is not consistency among different operating
+ systems on how to use FIONREAD.
+
+ FreeBSD, Linux and Solaris all expect the 3rd argument to
+ ioctl() to be an int, which is normally 32-bit even on 64-bit
+ machines.
+
+ IRIX, on the other hand, expects a size_t, which is 64-bit on
+ 64-bit machines.
+
+ So, the solution is to use size_t initialized to zero to make
+ sure all bits are set to zero, preventing underflow with the
+ FreeBSD/Linux/Solaris ioctls.
+ */
+ size_t nbytes = 0;
+ // gives shorter than true amounts on Unix domain sockets.
+ qint64 available = 0;
+ if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
+ available = (qint64) *((int *) &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.
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_storage storage;
+ sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<sockaddr_in6 *>(&storage);
+ storagePtrIPv6->sin6_port = 0;
+#else
+ struct sockaddr storage;
+#endif
+ sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage);
+ storagePtr->sa_family = 0;
+
+ sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage);
+ storagePtrIPv4->sin_port = 0;
+ QT_SOCKLEN_T storageSize = sizeof(storage);
+
+ // 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, storagePtr, &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)
+{
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_storage aa;
+#else
+ struct sockaddr_in aa;
+#endif
+ 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, (struct sockaddr *)&aa, &sz);
+ } while (recvFromResult == -1 && errno == EINTR);
+
+ if (recvFromResult == -1) {
+ setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
+ } else if (port || address) {
+ qt_socket_getPortAndAddress((struct sockaddr *) &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;
+ do {
+ sentBytes = ::sendto(socketDescriptor, data, len,
+ 0, sockAddrPtr, sockAddrSize);
+ } while (sentBytes == -1 && errno == EINTR);
+
+ 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;
+
+#if !defined(QT_NO_IPV6)
+ struct sockaddr_storage sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ struct sockaddr *sockAddrPtr = (struct sockaddr *) &sa;
+ QT_SOCKLEN_T sockAddrSize = sizeof(sa);
+
+ // Determine local address
+ memset(&sa, 0, sizeof(sa));
+ if (::getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(sockAddrPtr, &localPort, &localAddress);
+
+ // Determine protocol family
+ switch (sockAddrPtr->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, sockAddrPtr, &sockAddrSize))
+ qt_socket_getPortAndAddress(sockAddrPtr, &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
+ ::close(socketDescriptor);
+}
+
+qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
+{
+ Q_Q(QNativeSocketEngine);
+
+ // ignore the SIGPIPE signal
+ qt_ignore_sigpipe();
+
+ // loop while ::write() returns -1 and errno == EINTR, in case
+ // of an interrupting signal.
+ ssize_t writtenBytes;
+ do {
+ writtenBytes = ::write(socketDescriptor, data, len);
+ } while (writtenBytes < 0 && errno == EINTR);
+
+ 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::unbufferedRead: Invalid socket");
+ return -1;
+ }
+
+ ssize_t r = 0;
+ do {
+ r = ::read(socketDescriptor, data, maxSize);
+ } while (r == -1 && errno == EINTR);
+
+ 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:
+ setError(QAbstractSocket::NetworkError, ReadErrorString);
+ break;
+ case ECONNRESET:
+ 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;
+
+ QTime timer;
+ timer.start();
+
+ int retval;
+ do {
+ if (selectForRead)
+ retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
+ else
+ retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
+
+ if (retval != -1 || errno != EINTR)
+ break;
+
+ if (timeout > 0) {
+ // recalculate the timeout
+ timeout -= timer.elapsed();
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ if (timeout < 0) {
+ // oops, timeout turned negative?
+ retval = -1;
+ break;
+ }
+ }
+ } while (true);
+
+ 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;
+
+ QTime timer;
+ timer.start();
+
+ int ret;
+ do {
+ ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
+ if (ret != -1 || errno != EINTR)
+ break;
+
+ if (timeout > 0) {
+ // recalculate the timeout
+ timeout -= timer.elapsed();
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ if (timeout < 0) {
+ // oops, timeout turned negative?
+ ret = -1;
+ break;
+ }
+ }
+ } while (true);
+ 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..d140be2c51
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -0,0 +1,1211 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <winsock2.h>
+
+#include "qnativesocketengine_p.h"
+
+#include <qabstracteventdispatcher.h>
+#include <qsocketnotifier.h>
+#include <qdebug.h>
+#include <qdatetime.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
+
+#if !defined (QT_NO_IPV6)
+
+// Use our own defines and structs which we know are correct
+# define QT_SS_MAXSIZE 128
+# define QT_SS_ALIGNSIZE (sizeof(__int64))
+# 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];
+ __int64 __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 {
+ u_char qt_s6_addr[16];
+};
+typedef struct {
+ short sin6_family; /* AF_INET6 */
+ u_short sin6_port; /* Transport level port number */
+ u_long sin6_flowinfo; /* IPv6 flow information */
+ struct qt_in6_addr sin6_addr; /* IPv6 address */
+ u_long sin6_scope_id; /* set of interfaces for a scope */
+} qt_sockaddr_in6;
+
+#else
+
+typedef void * qt_sockaddr_in6 ;
+
+
+#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, struct sockaddr *sa, quint16 *port, QHostAddress *address)
+{
+#if !defined (QT_NO_IPV6)
+ if (sa->sa_family == AF_INET6) {
+ qt_sockaddr_in6 *sa6 = (qt_sockaddr_in6 *)sa;
+ 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->sa_family == AF_INET) {
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+ 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;
+ 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)
+ // 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;
+ 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;
+ }
+
+ int v = -1;
+ QT_SOCKOPTLEN_T len = sizeof(v);
+ if (getsockopt(socketDescriptor, SOL_SOCKET, 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;
+ 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;
+ }
+
+ if (::setsockopt(socketDescriptor, SOL_SOCKET, 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;
+
+#if !defined (QT_NO_IPV6)
+ struct qt_sockaddr_storage sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ struct sockaddr *pSa = (struct sockaddr *) &sa;
+
+ QT_SOCKLEN_T sz = sizeof(sa);
+
+ memset(&sa, 0, sizeof(sa));
+ if (::getsockname(socketDescriptor, pSa, &sz) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, pSa, &localPort, &localAddress);
+ // Determine protocol family
+ switch (pSa->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, pSa, &sz) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, pSa, &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;
+ QT_SOCKLEN_T sockAddrSize;
+
+ 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;
+ }
+ }
+ // 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 &address, quint16 port)
+{
+ struct sockaddr_in sockAddrIPv4;
+ qt_sockaddr_in6 sockAddrIPv6;
+ struct sockaddr *sockAddrPtr;
+ QT_SOCKLEN_T sockAddrSize;
+
+ 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()) {
+ // Becuase 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;
+}
+
+
+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.
+#if !defined(QT_NO_IPV6)
+ qt_sockaddr_in6 storage;
+ qt_sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<qt_sockaddr_in6 *>(&storage);
+ storagePtrIPv6->sin6_port = 0;
+#else
+ struct sockaddr storage;
+#endif
+ sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage);
+ storagePtr->sa_family = 0;
+
+ sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage);
+ storagePtrIPv4->sin_port = 0;
+ QT_SOCKLEN_T storageSize = sizeof(storage);
+
+
+ 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, storagePtr, &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,
+ storagePtr, &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(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;
+
+#if !defined(QT_NO_IPV6)
+ qt_sockaddr_storage aa;
+#else
+ struct sockaddr_in aa;
+#endif
+ 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, (struct sockaddr *) &aa, &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 (win 9x) 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, (struct sockaddr *) &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;
+ QT_SOCKLEN_T sockAddrSize;
+
+ qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+
+ if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based && len > qint64(qt_socket_getMaxMsgSize(socketDescriptor))) {
+ // WSAEMSGSIZE is not reliable enough (win 9x) so we check max size our self.
+ setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
+ } else {
+ 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;
+ // don't send more than 49152 per call to WSASendTo to avoid getting a WSAENOBUFS
+ for (;;) {
+ qint64 bytesToSend = qMin<qint64>(49152, len - ret);
+ 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);
+
+ if (socketRet != SOCKET_ERROR) {
+ if (ret == len)
+ break;
+ else
+ continue;
+ } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
+ break;
+ } else {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSAECONNRESET:
+ case WSAECONNABORTED:
+ ret = -1;
+ setError(QAbstractSocket::NetworkError, WriteErrorString);
+ q->close();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+#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:
+ setError(QAbstractSocket::NetworkError, ReadErrorString);
+ 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] = 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
+ ret = select(0, 0, &fds, 0, timeout < 0 ? 0 : &tv);
+
+ 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;
+
+ int ret = 0;
+
+ memset(&fdread, 0, sizeof(fd_set));
+ if (checkRead) {
+ fdread.fd_count = 1;
+ fdread.fd_array[0] = socketDescriptor;
+ }
+ memset(&fdwrite, 0, sizeof(fd_set));
+ if (checkWrite) {
+ fdwrite.fd_count = 1;
+ fdwrite.fd_array[0] = socketDescriptor;
+ }
+
+ 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, 0, timeout < 0 ? 0 : &tv);
+#else
+ ret = select(1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
+#endif
+ if (readEnabled)
+ readNotifier->setEnabled(true);
+
+ if (ret <= 0)
+ return ret;
+
+ *selectForRead = FD_ISSET(socketDescriptor, &fdread);
+ *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+
+ return ret;
+}
+
+void QNativeSocketEnginePrivate::nativeClose()
+{
+#if defined (QTCPSOCKETENGINE_DEBUG)
+ qDebug("QNativeSocketEnginePrivate::nativeClose()");
+#endif
+ linger l = {1, 0};
+ ::setsockopt(socketDescriptor, SOL_SOCKET, SO_DONTLINGER, (char*)&l, sizeof(l));
+ ::closesocket(socketDescriptor);
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
new file mode 100644
index 0000000000..c41e32dc27
--- /dev/null
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -0,0 +1,1850 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 "qdatetime.h"
+#include "qmutex.h"
+#include "qthread.h"
+#include "qcoreapplication.h"
+#include "qurl.h"
+#include "qauthenticator.h"
+#include <qendian.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int MaxWriteBufferSize = 128*1024;
+
+//#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;
+ QDateTime 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 = QDateTime::currentDateTime();
+ 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.secsTo(QDateTime::currentDateTime()) > 350) {
+ 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);
+ 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);
+ 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();
+ } 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();
+ }
+}
+
+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;
+ QTime 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;
+ 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;
+ QTime 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
+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
+
+int QSocks5SocketEngine::option(SocketOption option) const
+{
+ Q_UNUSED(option);
+ return -1;
+}
+
+bool QSocks5SocketEngine::setOption(SocketOption option, int value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+ 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;
+
+ QTime 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;
+
+ QTime 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;
+
+ QTime 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;
+ }
+ QSocks5SocketEngine *engine = new QSocks5SocketEngine(parent);
+ engine->setProxy(proxy);
+ return engine;
+}
+
+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..e11b1b6e27
--- /dev/null
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+ 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
+
+ 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/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
new file mode 100644
index 0000000000..c1fedc396d
--- /dev/null
+++ b/src/network/socket/qtcpserver.cpp
@@ -0,0 +1,643 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QTCPSERVER_DEBUG
+
+/*! \class QTcpServer
+
+ \brief The QTcpServer class provides a TCP-based server.
+
+ \reentrant
+ \ingroup io
+ \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.
+
+ \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 "qnativesocketengine_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;
+ }
+ 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();
+ d->socketEngine->deleteLater();
+ 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);
+ 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.
+
+ \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().
+
+ \sa newConnection(), nextPendingConnection()
+*/
+void QTcpServer::incomingConnection(int socketDescriptor)
+{
+#if defined (QTCPSERVER_DEBUG)
+ qDebug("QTcpServer::incomingConnection(%i)", socketDescriptor);
+#endif
+
+ QTcpSocket *socket = new QTcpSocket(this);
+ socket->setSocketDescriptor(socketDescriptor);
+ 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..71fdde8c2d
--- /dev/null
+++ b/src/network/socket/qtcpserver.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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);
+
+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..086a4206bc
--- /dev/null
+++ b/src/network/socket/qtcpsocket.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QTCPSOCKET_DEBUG
+
+/*!
+ \class QTcpSocket
+
+ \brief The QTcpSocket class provides a TCP socket.
+
+ \reentrant
+ \ingroup io
+ \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.
+
+ \sa QTcpServer, QUdpSocket, QFtp, QHttp, {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..ade70becae
--- /dev/null
+++ b/src/network/socket/qtcpsocket.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTCPSOCKET_H
+#define QTCPSOCKET_H
+
+#include <QtNetwork/qabstractsocket.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..3016cdbb5e
--- /dev/null
+++ b/src/network/socket/qtcpsocket_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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..820404db0f
--- /dev/null
+++ b/src/network/socket/qudpsocket.cpp
@@ -0,0 +1,424 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QUDPSOCKET_DEBUG
+
+/*! \class QUdpSocket
+
+ \reentrant
+ \brief The QUdpSocket class provides a UDP socket.
+
+ \ingroup io
+ \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.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0
+
+ 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} and
+ \l{network/broadcastreceiver}{Broadcast Receiver} examples
+ illustrate how to use QUdpSocket in applications.
+
+ \sa QTcpSocket
+*/
+
+/*! \enum QUdpSocket::BindFlag
+ \since 4.1
+
+ This enum describes the different flags you can pass to modify the
+ behavior of QUdpSocket::bind().
+
+ \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 "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() || socketEngine->protocol() != proto) {
+ 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);
+}
+
+/*!
+ 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 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..4e02f8402d
--- /dev/null
+++ b/src/network/socket/qudpsocket.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 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
+
+ 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..b1fe64ad97
--- /dev/null
+++ b/src/network/socket/socket.pri
@@ -0,0 +1,46 @@
+# Qt network socket
+
+HEADERS += socket/qabstractsocketengine_p.h \
+ socket/qnativesocketengine_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/qnativesocketengine.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
+
+unix:SOURCES += socket/qnativesocketengine_unix.cpp \
+ socket/qlocalsocket_unix.cpp \
+ socket/qlocalserver_unix.cpp
+
+
+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
+}
+
+