summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl/qsslsocket.cpp')
-rw-r--r--src/network/ssl/qsslsocket.cpp2072
1 files changed, 2072 insertions, 0 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
new file mode 100644
index 0000000..4abf865
--- /dev/null
+++ b/src/network/ssl/qsslsocket.cpp
@@ -0,0 +1,2072 @@
+/****************************************************************************
+**
+** 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 QSSLSOCKET_DEBUG
+
+/*!
+ \class QSslSocket
+ \brief The QSslSocket class provides an SSL encrypted socket for both
+ clients and servers.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslSocket establishes a secure, encrypted TCP connection you can
+ use for transmitting encrypted data. It can operate in both client
+ and server mode, and it supports modern SSL protocols, including
+ SSLv3 and TLSv1. By default, QSslSocket uses SSLv3, but you can
+ change the SSL protocol by calling setProtocol() as long as you do
+ it before the handshake has started.
+
+ SSL encryption operates on top of the existing TCP stream after
+ the socket enters the ConnectedState. There are two simple ways to
+ establish a secure connection using QSslSocket: With an immediate
+ SSL handshake, or with a delayed SSL handshake occurring after the
+ connection has been established in unencrypted mode.
+
+ The most common way to use QSslSocket is to construct an object
+ and start a secure connection by calling connectToHostEncrypted().
+ This method starts an immediate SSL handshake once the connection
+ has been established.
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 0
+
+ As with a plain QTcpSocket, QSslSocket enters the HostLookupState,
+ ConnectingState, and finally the ConnectedState, if the connection
+ is successful. The handshake then starts automatically, and if it
+ succeeds, the encrypted() signal is emitted to indicate the socket
+ has entered the encrypted state and is ready for use.
+
+ Note that data can be written to the socket immediately after the
+ return from connectToHostEncrypted() (i.e., before the encrypted()
+ signal is emitted). The data is queued in QSslSocket until after
+ the encrypted() signal is emitted.
+
+ An example of using the delayed SSL handshake to secure an
+ existing connection is the case where an SSL server secures an
+ incoming connection. Suppose you create an SSL server class as a
+ subclass of QTcpServer. You would override
+ QTcpServer::incomingConnection() with something like the example
+ below, which first constructs an instance of QSslSocket and then
+ calls setSocketDescriptor() to set the new socket's descriptor to
+ the existing one passed in. It then initiates the SSL handshake
+ by calling startServerEncryption().
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 1
+
+ If an error occurs, QSslSocket emits the sslErrors() signal. In this
+ case, if no action is taken to ignore the error(s), the connection
+ is dropped. To continue, despite the occurrence of an error, you
+ can call ignoreSslErrors(), either from within this slot after the
+ error occurs, or any time after construction of the QSslSocket and
+ before the connection is attempted. This will allow QSslSocket to
+ ignore the errors it encounters when establishing the identity of
+ the peer. Ignoring errors during an SSL handshake should be used
+ with caution, since a fundamental characteristic of secure
+ connections is that they should be established with a successful
+ handshake.
+
+ Once encrypted, you use QSslSocket as a regular QTcpSocket. When
+ readyRead() is emitted, you can call read(), canReadLine() and
+ readLine(), or getChar() to read decrypted data from QSslSocket's
+ internal buffer, and you can call write() or putChar() to write
+ data back to the peer. QSslSocket will automatically encrypt the
+ written data for you, and emit bytesWritten() once the data has
+ been written to the peer.
+
+ As a convenience, QSslSocket supports QTcpSocket's blocking
+ functions waitForConnected(), waitForReadyRead(),
+ waitForBytesWritten(), and waitForDisconnected(). It also provides
+ waitForEncrypted(), which will block the calling thread until an
+ encrypted connection has been established.
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 2
+
+ QSslSocket provides an extensive, easy-to-use API for handling
+ cryptographic ciphers, private keys, and local, peer, and
+ Certification Authority (CA) certificates. It also provides an API
+ for handling errors that occur during the handshake phase.
+
+ The following features can also be customized:
+
+ \list
+ \o The socket's cryptographic cipher suite can be customized before
+ the handshake phase with setCiphers() and setDefaultCiphers().
+ \o The socket's local certificate and private key can be customized
+ before the handshake phase with setLocalCertificate() and
+ setPrivateKey().
+ \o The CA certificate database can be extended and customized with
+ addCaCertificate(), addCaCertificates(), setCaCertificates(),
+ addDefaultCaCertificate(), addDefaultCaCertificates(), and
+ setDefaultCaCertificates().
+ \endlist
+
+ For more information about ciphers and certificates, refer to QSslCipher and
+ QSslCertificate.
+
+ This product includes software developed by the OpenSSL Project
+ for use in the OpenSSL Toolkit (\l{http://www.openssl.org/}).
+
+ \sa QSslCertificate, QSslCipher, QSslError
+*/
+
+/*!
+ \enum QSslSocket::SslMode
+
+ Describes the connection modes available for QSslSocket.
+
+ \value UnencryptedMode The socket is unencrypted. Its
+ behavior is identical to QTcpSocket.
+
+ \value SslClientMode The socket is a client-side SSL socket.
+ It is either alreayd encrypted, or it is in the SSL handshake
+ phase (see QSslSocket::isEncrypted()).
+
+ \value SslServerMode The socket is a server-side SSL socket.
+ It is either already encrypted, or it is in the SSL handshake
+ phase (see QSslSocket::isEncrypted()).
+*/
+
+/*!
+ \enum QSslSocket::PeerVerifyMode
+ \since 4.4
+
+ Describes the peer verification modes for QSslSocket. The default mode is
+ AutoVerifyPeer, which selects an appropriate mode depending on the
+ socket's QSocket::SslMode.
+
+ \value VerifyNone QSslSocket will not request a certificate from the
+ peer. You can set this mode if you are not interested in the identity of
+ the other side of the connection. The connection will still be encrypted,
+ and your socket will still send its local certificate to the peer if it's
+ requested.
+
+ \value QueryPeer QSslSocket will request a certificate from the peer, but
+ does not require this certificate to be valid. This is useful when you
+ want to display peer certificate details to the user without affecting the
+ actual SSL handshake. This mode is the default for servers.
+
+ \value VerifyPeer QSslSocket will request a certificate from the peer
+ during the SSL handshake phase, and requires that this certificate is
+ valid. On failure, QSslSocket will emit the QSslSocket::sslErrors()
+ signal. This mode is the default for clients.
+
+ \value AutoVerifyPeer QSslSocket will automaticaly use QueryPeer for
+ server sockets and VerifyPeer for client sockets.
+
+ \sa QSslSocket::peerVerifyMode()
+*/
+
+/*!
+ \fn QSslSocket::encrypted()
+
+ This signal is emitted when QSslSocket enters encrypted mode. After this
+ signal has been emitted, QSslSocket::isEncrypted() will return true, and
+ all further transmissions on the socket will be encrypted.
+
+ \sa QSslSocket::connectToHostEncrypted(), QSslSocket::isEncrypted()
+*/
+
+/*!
+ \fn QSslSocket::modeChanged(QSslSocket::SslMode mode)
+
+ This signal is emitted when QSslSocket changes from \l
+ QSslSocket::UnencryptedMode to either \l QSslSocket::SslClientMode or \l
+ QSslSocket::SslServerMode. \a mode is the new mode.
+
+ \sa QSslSocket::mode()
+*/
+
+/*!
+ \fn QSslSocket::encryptedBytesWritten(qint64 written)
+ \since 4.4
+
+ This signal is emitted when QSslSocket writes its encrypted data to the
+ network. The \a written parameter contains the number of bytes that were
+ successfully written.
+
+ \sa QIODevice::bytesWritten()
+*/
+
+/*!
+ \fn void QSslSocket::peerVerifyError(const QSslError &error)
+ \since 4.4
+
+ QSslSocket can emit this signal several times during the SSL handshake,
+ before encryption has been established, to indicate that an error has
+ occurred while establishing the identity of the peer. The \a error is
+ usually an indication that QSslSocket is unable to securely identify the
+ peer.
+
+ This signal provides you with an early indication when something's wrong.
+ By connecting to this signal, you can manually choose to tear down the
+ connection from inside the connected slot before the handshake has
+ completed. If no action is taken, QSslSocket will proceed to emitting
+ QSslSocket::sslErrors().
+
+ \sa sslErrors()
+*/
+
+/*!
+ \fn void QSslSocket::sslErrors(const QList<QSslError> &errors);
+
+ QSslSocket emits this signal after the SSL handshake to indicate that one
+ or more errors have occurred while establishing the identity of the
+ peer. The errors are usually an indication that QSslSocket is unable to
+ securely identify the peer. Unless any action is taken, the connection
+ will be dropped after this signal has been emitted.
+
+ If you want to continue connecting despite the errors that have occurred,
+ you must call QSslSocket::ignoreSslErrors() from inside a slot connected to
+ this signal. If you need to access the error list at a later point, you
+ can call sslErrors() (without arguments).
+
+ \a errors contains one or more errors that prevent QSslSocket from
+ verifying the identity of the peer.
+
+ Note: You cannot use Qt::QueuedConnection when connecting to this signal,
+ or calling QSslSocket::ignoreSslErrors() will have no effect.
+
+ \sa peerVerifyError()
+*/
+
+#include "qsslcipher.h"
+#include "qsslsocket.h"
+#include "qsslsocket_openssl_p.h"
+#include "qsslconfiguration_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qhostinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ 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;
+}
+
+class QSslSocketGlobalData
+{
+public:
+ QSslSocketGlobalData() : config(new QSslConfigurationPrivate) {}
+
+ QMutex mutex;
+ QList<QSslCipher> supportedCiphers;
+ QExplicitlySharedDataPointer<QSslConfigurationPrivate> config;
+};
+Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
+
+/*!
+ Constructs a QSslSocket object. \a parent is passed to QObject's
+ constructor. The new socket's \l {QSslCipher} {cipher} suite is
+ set to the one returned by the static method defaultCiphers().
+*/
+QSslSocket::QSslSocket(QObject *parent)
+ : QTcpSocket(*new QSslSocketBackendPrivate, parent)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::QSslSocket(" << parent << "), this =" << (void *)this;
+#endif
+ d->q_ptr = this;
+ d->init();
+}
+
+/*!
+ Destroys the QSslSocket.
+*/
+QSslSocket::~QSslSocket()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::~QSslSocket(), this =" << (void *)this;
+#endif
+ delete d->plainSocket;
+ d->plainSocket = 0;
+}
+
+/*!
+ Starts an encrypted connection to the device \a hostName on \a
+ port, using \a mode as the \l OpenMode. This is equivalent to
+ calling connectToHost() to establish the connection, followed by a
+ call to startClientEncryption().
+
+ QSslSocket first enters the HostLookupState. Then, after entering
+ either the event loop or one of the waitFor...() functions, it
+ enters the ConnectingState, emits connected(), and then initiates
+ the SSL client handshake. At each state change, QSslSocket emits
+ signal stateChanged().
+
+ After initiating the SSL client handshake, if the identity of the
+ peer can't be established, signal sslErrors() is emitted. If you
+ want to ignore the errors and continue connecting, you must call
+ ignoreSslErrors(), either from inside a slot function connected to
+ the sslErrors() signal, or prior to entering encrypted mode. If
+ ignoreSslErrors is not called, the connection is dropped, signal
+ disconnected() is emitted, and QSslSocket returns to the
+ UnconnectedState.
+
+ If the SSL handshake is successful, QSslSocket emits encrypted().
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 3
+
+ \bold{Note:} The example above shows that text can be written to
+ the socket immediately after requesting the encrypted connection,
+ before the encrypted() signal has been emitted. In such cases, the
+ text is queued in the object and written to the socket \e after
+ the connection is established and the encrypted() signal has been
+ emitted.
+
+ The default for \a mode is \l ReadWrite.
+
+ If you want to create a QSslSocket on the server side of a connection, you
+ should instead call startServerEncryption() upon receiving the incoming
+ connection through QTcpServer.
+
+ \sa connectToHost(), startClientEncryption(), waitForConnected(), waitForEncrypted()
+*/
+void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode)
+{
+ Q_D(QSslSocket);
+ if (d->state == ConnectedState || d->state == ConnectingState) {
+ qWarning("QSslSocket::connectToHostEncrypted() called when already connecting/connected");
+ return;
+ }
+
+ d->init();
+ d->autoStartHandshake = true;
+ d->initialized = true;
+
+ // Note: When connecting to localhost, some platforms (e.g., HP-UX and some BSDs)
+ // establish the connection immediately (i.e., first attempt).
+ connectToHost(hostName, port, mode);
+}
+
+/*!
+ \since 4.6
+
+ Variant of connectToHostEncrypted that enables to use a different hostname (\a sslPeerName)
+ for the certificate validation than the one used for the TCP connection (\a hostName).
+
+ \sa connectToHostEncrypted()
+*/
+void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port,
+ const QString &sslPeerName, OpenMode mode)
+{
+ Q_D(QSslSocket);
+ if (d->state == ConnectedState || d->state == ConnectingState) {
+ qWarning("QSslSocket::connectToHostEncrypted() called when already connecting/connected");
+ return;
+ }
+
+ d->init();
+ d->autoStartHandshake = true;
+ d->initialized = true;
+ d->verificationPeerName = sslPeerName;
+
+ // Note: When connecting to localhost, some platforms (e.g., HP-UX and some BSDs)
+ // establish the connection immediately (i.e., first attempt).
+ connectToHost(hostName, port, mode);
+}
+
+/*!
+ Initializes QSslSocket 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 state.
+
+ \bold{Note:} It is not possible to initialize two sockets with the same
+ native socket descriptor.
+
+ \sa socketDescriptor()
+*/
+bool QSslSocket::setSocketDescriptor(int socketDescriptor, SocketState state, OpenMode openMode)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << ","
+ << state << "," << openMode << ")";
+#endif
+ if (!d->plainSocket)
+ d->createPlainSocket(openMode);
+ bool retVal = d->plainSocket->setSocketDescriptor(socketDescriptor, state, openMode);
+ d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
+ setSocketError(d->plainSocket->error());
+ setSocketState(state);
+ setOpenMode(openMode);
+ setLocalPort(d->plainSocket->localPort());
+ setLocalAddress(d->plainSocket->localAddress());
+ setPeerPort(d->plainSocket->peerPort());
+ setPeerAddress(d->plainSocket->peerAddress());
+ setPeerName(d->plainSocket->peerName());
+ return retVal;
+}
+
+/*!
+ Returns the current mode for the socket; either UnencryptedMode, where
+ QSslSocket behaves identially to QTcpSocket, or one of SslClientMode or
+ SslServerMode, where the client is either negotiating or in encrypted
+ mode.
+
+ When the mode changes, QSslSocket emits modeChanged()
+
+ \sa SslMode
+*/
+QSslSocket::SslMode QSslSocket::mode() const
+{
+ Q_D(const QSslSocket);
+ return d->mode;
+}
+
+/*!
+ Returns true if the socket is encrypted; otherwise, false is returned.
+
+ An encrypted socket encrypts all data that is written by calling write()
+ or putChar() before the data is written to the network, and descrypts all
+ incoming data as the data is received from the network, before you call
+ read(), readLine() or getChar().
+
+ QSslSocket emits encrypted() when it enters encrypted mode.
+
+ You can call sessionCipher() to find which cryptographic cipher is used to
+ encrypt and decrypt your data.
+
+ \sa mode()
+*/
+bool QSslSocket::isEncrypted() const
+{
+ Q_D(const QSslSocket);
+ return d->connectionEncrypted;
+}
+
+/*!
+ Returns the socket's SSL protocol. By default, \l QSsl::SslV3 is used.
+
+ \sa setProtocol()
+*/
+QSsl::SslProtocol QSslSocket::protocol() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.protocol;
+}
+
+/*!
+ Sets the socket's SSL protocol to \a protocol. This will affect the next
+ initiated handshake; calling this function on an already-encrypted socket
+ will not affect the socket's protocol.
+*/
+void QSslSocket::setProtocol(QSsl::SslProtocol protocol)
+{
+ Q_D(QSslSocket);
+ d->configuration.protocol = protocol;
+}
+
+/*!
+ \since 4.4
+
+ Returns the socket's verify mode. This mode mode decides whether
+ QSslSocket should request a certificate from the peer (i.e., the client
+ requests a certificate from the server, or a server requesting a
+ certificate from the client), and whether it should require that this
+ certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients, QueryPeer for clients.
+
+ \sa setPeerVerifyMode(), peerVerifyDepth(), mode()
+*/
+QSslSocket::PeerVerifyMode QSslSocket::peerVerifyMode() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerVerifyMode;
+}
+
+/*!
+ \since 4.4
+
+ Sets the socket's verify mode to \a mode. This mode decides whether
+ QSslSocket should request a certificate from the peer (i.e., the client
+ requests a certificate from the server, or a server requesting a
+ certificate from the client), and whether it should require that this
+ certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients, QueryPeer for clients.
+
+ Setting this mode after encryption has started has no effect on the
+ current connection.
+
+ \sa peerVerifyMode(), setPeerVerifyDepth(), mode()
+*/
+void QSslSocket::setPeerVerifyMode(QSslSocket::PeerVerifyMode mode)
+{
+ Q_D(QSslSocket);
+ d->configuration.peerVerifyMode = mode;
+}
+
+/*!
+ \since 4.4
+
+ Returns the maximum number of certificates in the peer's certificate chain
+ to be checked during the SSL handshake phase, or 0 (the default) if no
+ maximum depth has been set, indicating that the whole certificate chain
+ should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa setPeerVerifyDepth(), peerVerifyMode()
+*/
+int QSslSocket::peerVerifyDepth() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerVerifyDepth;
+}
+
+/*!
+ \since 4.4
+
+ Sets the maximum number of certificates in the peer's certificate chain to
+ be checked during the SSL handshake phase, to \a depth. Setting a depth of
+ 0 means that no maximum depth is set, indicating that the whole
+ certificate chain should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa peerVerifyDepth(), setPeerVerifyMode()
+*/
+void QSslSocket::setPeerVerifyDepth(int depth)
+{
+ Q_D(QSslSocket);
+ if (depth < 0) {
+ qWarning("QSslSocket::setPeerVerifyDepth: cannot set negative depth of %d", depth);
+ return;
+ }
+ d->configuration.peerVerifyDepth = depth;
+}
+
+/*!
+ \reimp
+
+ Returns the number of decrypted bytes that are immediately available for
+ reading.
+*/
+qint64 QSslSocket::bytesAvailable() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::bytesAvailable() + (d->plainSocket ? d->plainSocket->bytesAvailable() : 0);
+ return QIODevice::bytesAvailable() + d->readBuffer.size();
+}
+
+/*!
+ \reimp
+
+ Returns the number of unencrypted bytes that are waiting to be encrypted
+ and written to the network.
+*/
+qint64 QSslSocket::bytesToWrite() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket ? d->plainSocket->bytesToWrite() : 0;
+ return d->writeBuffer.size();
+}
+
+/*!
+ \since 4.4
+
+ Returns the number of encrypted bytes that are awaiting decryption.
+ Normally, this function will return 0 because QSslSocket decrypts its
+ incoming data as soon as it can.
+*/
+qint64 QSslSocket::encryptedBytesAvailable() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return 0;
+ return d->plainSocket->bytesAvailable();
+}
+
+/*!
+ \since 4.4
+
+ Returns the number of encrypted bytes that are waiting to be written to
+ the network.
+*/
+qint64 QSslSocket::encryptedBytesToWrite() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return 0;
+ return d->plainSocket->bytesToWrite();
+}
+
+/*!
+ \reimp
+
+ Returns true if you can read one while line (terminated by a single ASCII
+ '\n' character) of decrypted characters; otherwise, false is returned.
+*/
+bool QSslSocket::canReadLine() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::canReadLine() || (d->plainSocket && d->plainSocket->canReadLine());
+ return QIODevice::canReadLine() || (!d->readBuffer.isEmpty() && d->readBuffer.canReadLine());
+}
+
+/*!
+ \reimp
+*/
+void QSslSocket::close()
+{
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::close()";
+#endif
+ QTcpSocket::close();
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::atEnd() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::atEnd() && (!d->plainSocket || d->plainSocket->atEnd());
+ return QIODevice::atEnd() && d->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 QSslSocket 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 from QAbstractSocket::flush()
+bool QSslSocket::flush()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::flush()";
+#endif
+ if (d->mode != UnencryptedMode)
+ // encrypt any unencrypted bytes in our buffer
+ d->transmit();
+
+ return d->plainSocket ? d->plainSocket->flush() : false;
+}
+
+/*!
+ \since 4.4
+
+ Sets the size of QSslSocket's internal read buffer to be \a size bytes.
+*/
+void QSslSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QSslSocket);
+ d->readBufferMaxSize = size;
+
+ // set the plain socket's buffer size to 1k if we have a limit
+ // see also the same logic in QSslSocketPrivate::createPlainSocket
+ if (d->plainSocket) {
+ if (d->mode == UnencryptedMode)
+ d->plainSocket->setReadBufferSize(size);
+ else
+ d->plainSocket->setReadBufferSize(size ? 1024 : 0);
+ }
+}
+
+/*!
+ Aborts the current connection and resets the socket. Unlike
+ disconnectFromHost(), this function immediately closes the socket,
+ clearing any pending data in the write buffer.
+
+ \sa disconnectFromHost(), close()
+*/
+void QSslSocket::abort()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::abort()";
+#endif
+ if (d->plainSocket)
+ d->plainSocket->abort();
+ close();
+}
+
+/*!
+ \since 4.4
+
+ Returns the socket's SSL configuration state. The default SSL
+ configuration of a socket is to use the default ciphers,
+ default CA certificates, no local private key or certificate.
+
+ The SSL configuration also contains fields that can change with
+ time without notice.
+
+ \sa localCertificate(), peerCertificate(), peerCertificateChain(),
+ sessionCipher(), privateKey(), ciphers(), caCertificates()
+*/
+QSslConfiguration QSslSocket::sslConfiguration() const
+{
+ Q_D(const QSslSocket);
+
+ // create a deep copy of our configuration
+ QSslConfigurationPrivate *copy = new QSslConfigurationPrivate(d->configuration);
+ copy->ref = 0; // the QSslConfiguration constructor refs up
+ copy->sessionCipher = d->sessionCipher();
+
+ return QSslConfiguration(copy);
+}
+
+/*!
+ \since 4.4
+
+ Sets the socket's SSL configuration to be the contents of \a configuration.
+ This function sets the local certificate, the ciphers, the private key and the CA
+ certificates to those stored in \a configuration.
+
+ It is not possible to set the SSL-state related fields.
+
+ \sa setLocalCertificate(), setPrivateKey(), setCaCertificates(), setCiphers()
+*/
+void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
+{
+ Q_D(QSslSocket);
+ d->configuration.localCertificate = configuration.localCertificate();
+ d->configuration.privateKey = configuration.privateKey();
+ d->configuration.ciphers = configuration.ciphers();
+ d->configuration.caCertificates = configuration.caCertificates();
+ d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
+ d->configuration.peerVerifyMode = configuration.peerVerifyMode();
+ d->configuration.protocol = configuration.protocol();
+}
+
+/*!
+ Sets the socket's local certificate to \a certificate. The local
+ certificate is necessary if you need to confirm your identity to the
+ peer. It is used together with the private key; if you set the local
+ certificate, you must also set the private key.
+
+ The local certificate and private key are always necessary for server
+ sockets, but are also rarely used by client sockets if the server requires
+ the client to authenticate.
+
+ \sa localCertificate(), setPrivateKey()
+*/
+void QSslSocket::setLocalCertificate(const QSslCertificate &certificate)
+{
+ Q_D(QSslSocket);
+ d->configuration.localCertificate = certificate;
+}
+
+/*!
+ \overload
+
+ Sets the socket's local \l {QSslCertificate} {certificate} to the
+ first one found in file \a path, which is parsed according to the
+ specified \a format.
+*/
+void QSslSocket::setLocalCertificate(const QString &path,
+ QSsl::EncodingFormat format)
+{
+ Q_D(QSslSocket);
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+ d->configuration.localCertificate = QSslCertificate(file.readAll(), format);
+}
+
+/*!
+ Returns the socket's local \l {QSslCertificate} {certificate}, or
+ an empty certificate if no local certificate has been assigned.
+
+ \sa setLocalCertificate(), privateKey()
+*/
+QSslCertificate QSslSocket::localCertificate() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.localCertificate;
+}
+
+/*!
+ Returns the peer's digital certificate (i.e., the immediate
+ certificate of the host you are connected to), or a null
+ certificate, if the peer has not assigned a certificate.
+
+ The peer certificate is checked automatically during the
+ handshake phase, so this function is normally used to fetch
+ the certificate for display or for connection diagnostic
+ purposes. It contains information about the peer, including
+ its host name, the certificate issuer, and the peer's public
+ key.
+
+ Because the peer certificate is set during the handshake phase, it
+ is safe to access the peer certificate from a slot connected to
+ the sslErrors() signal or the encrypted() signal.
+
+ If a null certificate is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to check the peer's complete chain of certificates,
+ use peerCertificateChain() to get them all at once.
+
+ \sa peerCertificateChain()
+*/
+QSslCertificate QSslSocket::peerCertificate() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerCertificate;
+}
+
+/*!
+ Returns the peer's chain of digital certificates, or an empty list
+ of certificates.
+
+ Peer certificates are checked automatically during the handshake
+ phase. This function is normally used to fetch certificates for
+ display, or for performing connection diagnostics. Certificates
+ contain information about the peer and the certificate issuers,
+ including host name, issuer names, and issuer public keys.
+
+ The peer certificates are set in QSslSocket during the handshake
+ phase, so it is safe to call this function from a slot connected
+ to the sslErrors() signal or the encrypted() signal.
+
+ If an empty list is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to get only the peer's immediate certificate, use
+ peerCertificate().
+
+ \sa peerCertificate()
+*/
+QList<QSslCertificate> QSslSocket::peerCertificateChain() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerCertificateChain;
+}
+
+/*!
+ Returns the socket's cryptographic \l {QSslCipher} {cipher}, or a
+ null cipher if the connection isn't encrypted. The socket's cipher
+ for the session is set during the handshake phase. The cipher is
+ used to encrypt and decrypt data transmitted through the socket.
+
+ QSslSocket also provides functions for setting the ordered list of
+ ciphers from which the handshake phase will eventually select the
+ session cipher. This ordered list must be in place before the
+ handshake phase begins.
+
+ \sa ciphers(), setCiphers(), setDefaultCiphers(), defaultCiphers(),
+ supportedCiphers()
+*/
+QSslCipher QSslSocket::sessionCipher() const
+{
+ Q_D(const QSslSocket);
+ return d->sessionCipher();
+}
+
+/*!
+ Sets the socket's private \l {QSslKey} {key} to \a key. The
+ private key and the local \l {QSslCertificate} {certificate} are
+ used by clients and servers that must prove their identity to
+ SSL peers.
+
+ Both the key and the local certificate are required if you are
+ creating an SSL server socket. If you are creating an SSL client
+ socket, the key and local certificate are required if your client
+ must identify itself to an SSL server.
+
+ \sa privateKey(), setLocalCertificate()
+*/
+void QSslSocket::setPrivateKey(const QSslKey &key)
+{
+ Q_D(QSslSocket);
+ d->configuration.privateKey = key;
+}
+
+/*!
+ \overload
+
+ Reads the string in file \a fileName and decodes it using
+ a specified \a algorithm and encoding \a format to construct
+ an \l {QSslKey} {SSL key}. If the encoded key is encrypted,
+ \a passPhrase is used to decrypt it.
+
+ The socket's private key is set to the constructed key. The
+ private key and the local \l {QSslCertificate} {certificate} are
+ used by clients and servers that must prove their identity to SSL
+ peers.
+
+ Both the key and the local certificate are required if you are
+ creating an SSL server socket. If you are creating an SSL client
+ socket, the key and local certificate are required if your client
+ must identify itself to an SSL server.
+
+ \sa privateKey(), setLocalCertificate()
+*/
+void QSslSocket::setPrivateKey(const QString &fileName, QSsl::KeyAlgorithm algorithm,
+ QSsl::EncodingFormat format, const QByteArray &passPhrase)
+{
+ Q_D(QSslSocket);
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ d->configuration.privateKey = QSslKey(file.readAll(), algorithm,
+ format, QSsl::PrivateKey, passPhrase);
+ }
+}
+
+/*!
+ Returns this socket's private key.
+
+ \sa setPrivateKey(), localCertificate()
+*/
+QSslKey QSslSocket::privateKey() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.privateKey;
+}
+
+/*!
+ Returns this socket's current cryptographic cipher suite. This
+ list is used during the socket's handshake phase for choosing a
+ session cipher. The returned list of ciphers is ordered by
+ descending preference. (i.e., the first cipher in the list is the
+ most preferred cipher). The session cipher will be the first one
+ in the list that is also supported by the peer.
+
+ By default, the handshake phase can choose any of the ciphers
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of ciphers supported by this system's
+ SSL libraries is returned by supportedCiphers(). You can restrict
+ the list of ciphers used for choosing the session cipher for this
+ socket by calling setCiphers() with a subset of the supported
+ ciphers. You can revert to using the entire set by calling
+ setCiphers() with the list returned by supportedCiphers().
+
+ You can restrict the list of ciphers used for choosing the session
+ cipher for \e all sockets by calling setDefaultCiphers() with a
+ subset of the supported ciphers. You can revert to using the
+ entire set by calling setCiphers() with the list returned by
+ supportedCiphers().
+
+ \sa setCiphers(), defaultCiphers(), setDefaultCiphers(), supportedCiphers()
+*/
+QList<QSslCipher> QSslSocket::ciphers() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.ciphers;
+}
+
+/*!
+ Sets the cryptographic cipher suite for this socket to \a ciphers,
+ which must contain a subset of the ciphers in the list returned by
+ supportedCiphers().
+
+ Restricting the cipher suite must be done before the handshake
+ phase, where the session cipher is chosen.
+
+ \sa ciphers(), setDefaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setCiphers(const QList<QSslCipher> &ciphers)
+{
+ Q_D(QSslSocket);
+ d->configuration.ciphers = ciphers;
+}
+
+/*!
+ Sets the cryptographic cipher suite for this socket to \a ciphers, which
+ is a colon-separated list of cipher suite names. The ciphers are listed in
+ order of preference, starting with the most preferred cipher. For example:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 4
+
+ Each cipher name in \a ciphers must be the name of a cipher in the
+ list returned by supportedCiphers(). Restricting the cipher suite
+ must be done before the handshake phase, where the session cipher
+ is chosen.
+
+ \sa ciphers(), setDefaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setCiphers(const QString &ciphers)
+{
+ Q_D(QSslSocket);
+ d->configuration.ciphers.clear();
+ foreach (QString cipherName, ciphers.split(QLatin1String(":"),QString::SkipEmptyParts)) {
+ for (int i = 0; i < 3; ++i) {
+ // ### Crude
+ QSslCipher cipher(cipherName, QSsl::SslProtocol(i));
+ if (!cipher.isNull())
+ d->configuration.ciphers << cipher;
+ }
+ }
+}
+
+/*!
+ Sets the default cryptographic cipher suite for all sockets in
+ this application to \a ciphers, which must contain a subset of the
+ ciphers in the list returned by supportedCiphers().
+
+ Restricting the default cipher suite only affects SSL sockets
+ that perform their handshake phase after the default cipher
+ suite has been changed.
+
+ \sa setCiphers(), defaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultCiphers(ciphers);
+}
+
+/*!
+ Returns the default cryptographic cipher suite for all sockets in
+ this application. This list is used during the socket's handshake
+ phase when negotiating with the peer to choose a session cipher.
+ The list is ordered by preference (i.e., the first cipher in the
+ list is the most preferred cipher).
+
+ By default, the handshake phase can choose any of the ciphers
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of ciphers supported by this system's
+ SSL libraries is returned by supportedCiphers().
+
+ \sa supportedCiphers()
+*/
+QList<QSslCipher> QSslSocket::defaultCiphers()
+{
+ return QSslSocketPrivate::defaultCiphers();
+}
+
+/*!
+ Returns the list of cryptographic ciphers supported by this
+ system. This list is set by the system's SSL libraries and may
+ vary from system to system.
+
+ \sa defaultCiphers(), ciphers(), setCiphers()
+*/
+QList<QSslCipher> QSslSocket::supportedCiphers()
+{
+ return QSslSocketPrivate::supportedCiphers();
+}
+
+/*!
+ Searches all files in the \a path for certificates encoded in the
+ specified \a format and adds them to this socket's CA certificate
+ database. \a path can be explicit, or it can contain wildcards in
+ the format specified by \a syntax. Returns true if one or more
+ certificates are added to the socket's CA certificate database;
+ otherwise returns false.
+
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ For more precise control, use addCaCertificate().
+
+ \sa addCaCertificate(), QSslCertificate::fromPath()
+*/
+bool QSslSocket::addCaCertificates(const QString &path, QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax)
+{
+ Q_D(QSslSocket);
+ QList<QSslCertificate> certs = QSslCertificate::fromPath(path, format, syntax);
+ if (certs.isEmpty())
+ return false;
+
+ d->configuration.caCertificates += certs;
+ return true;
+}
+
+/*!
+ Adds the \a certificate to this socket's CA certificate database.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ To add multiple certificates, use addCaCertificates().
+
+ \sa caCertificates(), setCaCertificates()
+*/
+void QSslSocket::addCaCertificate(const QSslCertificate &certificate)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates += certificate;
+}
+
+/*!
+ Adds the \a certificates to this socket's CA certificate database.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ For more precise control, use addCaCertificate().
+
+ \sa caCertificates(), addDefaultCaCertificate()
+*/
+void QSslSocket::addCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates += certificates;
+}
+
+/*!
+ Sets this socket's CA certificate database to be \a certificates.
+ The certificate database must be set prior to the SSL handshake.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ The CA certificate database can be reset to the current default CA
+ certificate database by calling this function with the list of CA
+ certificates returned by defaultCaCertificates().
+
+ \sa defaultCaCertificates()
+*/
+void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates = certificates;
+}
+
+/*!
+ Returns this socket's CA certificate database. The CA certificate
+ database is used by the socket during the handshake phase to
+ validate the peer's certificate. It can be moodified prior to the
+ handshake with addCaCertificate(), addCaCertificates(), and
+ setCaCertificates().
+
+ \sa addCaCertificate(), addCaCertificates(), setCaCertificates()
+*/
+QList<QSslCertificate> QSslSocket::caCertificates() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.caCertificates;
+}
+
+/*!
+ Searches all files in the \a path for certificates with the
+ specified \a encoding and adds them to the default CA certificate
+ database. \a path can be an explicit file, or it can contain
+ wildcards in the format specified by \a syntax. Returns true if
+ any CA certificates are added to the default database.
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates(), addDefaultCaCertificate()
+*/
+bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat encoding,
+ QRegExp::PatternSyntax syntax)
+{
+ return QSslSocketPrivate::addDefaultCaCertificates(path, encoding, syntax);
+}
+
+/*!
+ Adds \a certificate to the default CA certificate database. Each
+ SSL socket's CA certificate database is initialized to the default
+ CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates()
+*/
+void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
+{
+ QSslSocketPrivate::addDefaultCaCertificate(certificate);
+}
+
+/*!
+ Adds \a certificates to the default CA certificate database. Each
+ SSL socket's CA certificate database is initialized to the default
+ CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates()
+*/
+void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ QSslSocketPrivate::addDefaultCaCertificates(certificates);
+}
+
+/*!
+ Sets the default CA certificate database to \a certificates. The
+ default CA certificate database is originally set to your system's
+ default CA certificate database. If no system default database is
+ found, Qt will provide its own default database. You can override
+ the default CA certificate database with your own CA certificate
+ database using this function.
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \sa addDefaultCaCertificate()
+*/
+void QSslSocket::setDefaultCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ QSslSocketPrivate::setDefaultCaCertificates(certificates);
+}
+
+/*!
+ Returns the current default CA certificate database. This database
+ is originally set to your system's default CA certificate database.
+ If no system default database is found, Qt will provide its own
+ default database. You can override the default CA certificate database
+ with your own CA certificate database using setDefaultCaCertificates().
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \sa caCertificates()
+*/
+QList<QSslCertificate> QSslSocket::defaultCaCertificates()
+{
+ return QSslSocketPrivate::defaultCaCertificates();
+}
+
+/*!
+ Returns the system default CA certificate database for your
+ system. This database is normally found in a standard place for
+ your system. If it is not found there, Qt will provide its own
+ default CA certificate database. The CA certificate database
+ returned by this function is used to initialize the database
+ returned by defaultCaCertificates(). You can replace that database
+ with your own with setDefaultCaCertificates().
+
+ \sa caCertificates(), defaultCaCertificates(), setDefaultCaCertificates()
+*/
+QList<QSslCertificate> QSslSocket::systemCaCertificates()
+{
+ QSslSocketPrivate::ensureInitialized();
+ return QSslSocketPrivate::systemCaCertificates();
+}
+
+/*!
+ Waits until the socket is connected, or \a msecs milliseconds,
+ whichever happens first. If the connection has been established,
+ this function returns true; otherwise it returns false.
+
+ \sa QAbstractSocket::waitForConnected()
+*/
+bool QSslSocket::waitForConnected(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ bool retVal = d->plainSocket->waitForConnected(msecs);
+ if (!retVal) {
+ setSocketState(d->plainSocket->state());
+ setSocketError(d->plainSocket->error());
+ setErrorString(d->plainSocket->errorString());
+ }
+ return retVal;
+}
+
+/*!
+ Waits until the socket has completed the SSL handshake and has
+ emitted encrypted(), or \a msecs milliseconds, whichever comes
+ first. If encrypted() has been emitted, this function returns
+ true; otherwise (e.g., the socket is disconnected, or the SSL
+ handshake fails), false is returned.
+
+ The following example waits up to one second for the socket to be
+ encrypted:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 5
+
+ If msecs is -1, this function will not time out.
+
+ \sa startClientEncryption(), startServerEncryption(), encrypted(), isEncrypted()
+*/
+bool QSslSocket::waitForEncrypted(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket || d->connectionEncrypted)
+ return false;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return false;
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ if (d->plainSocket->state() != QAbstractSocket::ConnectedState) {
+ // Wait until we've entered connected state.
+ if (!d->plainSocket->waitForConnected(msecs))
+ return false;
+ }
+
+ while (!d->connectionEncrypted) {
+ // Start the handshake, if this hasn't been started yet.
+ if (d->mode == UnencryptedMode)
+ startClientEncryption();
+ // Loop, waiting until the connection has been encrypted or an error
+ // occurs.
+ if (!d->plainSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed())))
+ return false;
+ }
+ return d->connectionEncrypted;
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return d->plainSocket->waitForReadyRead(msecs);
+
+ // This function must return true if and only if readyRead() *was* emitted.
+ // So we initialize "readyReadEmitted" to false and check if it was set to true.
+ // waitForReadyRead() could be called recursively, so we can't use the same variable
+ // (the inner waitForReadyRead() may fail, but the outer one still succeeded)
+ bool readyReadEmitted = false;
+ bool *previousReadyReadEmittedPointer = d->readyReadEmittedPointer;
+ d->readyReadEmittedPointer = &readyReadEmitted;
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs)) {
+ d->readyReadEmittedPointer = previousReadyReadEmittedPointer;
+ return false;
+ }
+ }
+
+ if (!d->writeBuffer.isEmpty()) {
+ // empty our cleartext write buffer first
+ d->transmit();
+ }
+
+ // test readyReadEmitted first because either operation above
+ // (waitForEncrypted or transmit) may have set it
+ while (!readyReadEmitted &&
+ d->plainSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ }
+
+ d->readyReadEmittedPointer = previousReadyReadEmittedPointer;
+ return readyReadEmitted;
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket->waitForBytesWritten(msecs);
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs))
+ return false;
+ }
+ if (!d->writeBuffer.isEmpty()) {
+ // empty our cleartext write buffer first
+ d->transmit();
+ }
+
+ return d->plainSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
+}
+
+/*!
+ Waits until the socket has disconnected or \a msecs milliseconds,
+ whichever comes first. If the connection has been disconnected,
+ this function returns true; otherwise it returns false.
+
+ \sa QAbstractSocket::waitForDisconnected()
+*/
+bool QSslSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QSslSocket);
+
+ // require calling connectToHost() before waitForDisconnected()
+ if (state() == UnconnectedState) {
+ qWarning("QSslSocket::waitForDisconnected() is not allowed in UnconnectedState");
+ return false;
+ }
+
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket->waitForDisconnected(msecs);
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs))
+ return false;
+ }
+ bool retVal = d->plainSocket->waitForDisconnected(qt_timeout_value(msecs, stopWatch.elapsed()));
+ if (!retVal) {
+ setSocketState(d->plainSocket->state());
+ setSocketError(d->plainSocket->error());
+ setErrorString(d->plainSocket->errorString());
+ }
+ return retVal;
+}
+
+/*!
+ Returns a list of the last SSL errors that occurred. This is the
+ same list as QSslSocket passes via the sslErrors() signal. If the
+ connection has been encrypted with no errors, this function will
+ return an empty list.
+
+ \sa connectToHostEncrypted()
+*/
+QList<QSslError> QSslSocket::sslErrors() const
+{
+ Q_D(const QSslSocket);
+ return d->sslErrors;
+}
+
+/*!
+ Returns true if this platform supports SSL; otherwise, returns
+ false. If the platform doesn't support SSL, the socket will fail
+ in the connection phase.
+*/
+bool QSslSocket::supportsSsl()
+{
+ return QSslSocketPrivate::ensureInitialized();
+}
+
+/*!
+ Starts a delayed SSL handshake for a client connection. This
+ function can be called when the socket is in the \l ConnectedState
+ but still in the \l UnencryptedMode. If it is not yet connected,
+ or if it is already encrypted, this function has no effect.
+
+ Clients that implement STARTTLS functionality often make use of
+ delayed SSL handshakes. Most other clients can avoid calling this
+ function directly by using connectToHostEncrypted() instead, which
+ automatically performs the handshake.
+
+ \sa connectToHostEncrypted(), startServerEncryption()
+*/
+void QSslSocket::startClientEncryption()
+{
+ Q_D(QSslSocket);
+ if (d->mode != UnencryptedMode) {
+ qWarning("QSslSocket::startClientEncryption: cannot start handshake on non-plain connection");
+ return;
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::startClientEncryption()";
+#endif
+ d->mode = SslClientMode;
+ emit modeChanged(d->mode);
+ d->startClientEncryption();
+}
+
+/*!
+ Starts a delayed SSL handshake for a server connection. This
+ function can be called when the socket is in the \l ConnectedState
+ but still in \l UnencryptedMode. If it is not connected or it is
+ already encrypted, the function has no effect.
+
+ For server sockets, calling this function is the only way to
+ initiate the SSL handshake. Most servers will call this function
+ immediately upon receiving a connection, or as a result of having
+ received a protocol-specific command to enter SSL mode (e.g, the
+ server may respond to receiving the string "STARTTLS\r\n" by
+ calling this function).
+
+ The most common way to implement an SSL server is to create a
+ subclass of QTcpServer and reimplement
+ QTcpServer::incomingConnection(). The returned socket descriptor
+ is then passed to QSslSocket::setSocketDescriptor().
+
+ \sa connectToHostEncrypted(), startClientEncryption()
+*/
+void QSslSocket::startServerEncryption()
+{
+ Q_D(QSslSocket);
+ if (d->mode != UnencryptedMode) {
+ qWarning("QSslSocket::startClientEncryption: cannot start handshake on non-plain connection");
+ return;
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::startServerEncryption()";
+#endif
+ d->mode = SslServerMode;
+ emit modeChanged(d->mode);
+ d->startServerEncryption();
+}
+
+/*!
+ This slot tells QSslSocket to ignore errors during QSslSocket's
+ handshake phase and continue connecting. If you want to continue
+ with the connection even if errors occur during the handshake
+ phase, then you must call this slot, either from a slot connected
+ to sslErrors(), or before the handshake phase. If you don't call
+ this slot, either in response to errors or before the handshake,
+ the connection will be dropped after the sslErrors() signal has
+ been emitted.
+
+ If there are no errors during the SSL handshake phase (i.e., the
+ identity of the peer is established with no problems), QSslSocket
+ will not emit the sslErrors() signal, and it is unnecessary to
+ call this function.
+
+ Ignoring errors that occur during an SSL handshake should be done
+ with caution. A fundamental characteristic of secure connections
+ is that they should be established with an error free handshake.
+
+ \sa sslErrors()
+*/
+void QSslSocket::ignoreSslErrors()
+{
+ Q_D(QSslSocket);
+ d->ignoreSslErrors = true;
+}
+
+/*!
+ \internal
+*/
+void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 port,
+ OpenMode openMode)
+{
+ Q_D(QSslSocket);
+ if (!d->initialized)
+ d->init();
+ d->initialized = false;
+
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::connectToHostImplementation("
+ << hostName << "," << port << "," << openMode << ")";
+#endif
+ if (!d->plainSocket) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "\tcreating internal plain socket";
+#endif
+ d->createPlainSocket(openMode);
+ }
+#ifndef QT_NO_NETWORKPROXY
+ d->plainSocket->setProxy(proxy());
+#endif
+ QIODevice::open(openMode);
+ d->plainSocket->connectToHost(hostName, port, openMode);
+ d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
+}
+
+/*!
+ \internal
+*/
+void QSslSocket::disconnectFromHostImplementation()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::disconnectFromHostImplementation()";
+#endif
+ if (!d->plainSocket)
+ return;
+ if (d->state == UnconnectedState)
+ return;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake) {
+ d->plainSocket->disconnectFromHost();
+ return;
+ }
+ if (d->state <= ConnectingState) {
+ d->pendingClose = true;
+ return;
+ }
+
+ // Perhaps emit closing()
+ if (d->state != ClosingState) {
+ d->state = ClosingState;
+ emit stateChanged(d->state);
+ }
+
+ if (!d->writeBuffer.isEmpty())
+ return;
+
+ if (d->mode == UnencryptedMode) {
+ d->plainSocket->disconnectFromHost();
+ } else {
+ d->disconnectFromHost();
+ }
+}
+
+/*!
+ \reimp
+*/
+qint64 QSslSocket::readData(char *data, qint64 maxlen)
+{
+ Q_D(QSslSocket);
+ qint64 readBytes = 0;
+
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake) {
+ readBytes = d->plainSocket->read(data, maxlen);
+ } else {
+ do {
+ const char *readPtr = d->readBuffer.readPointer();
+ int bytesToRead = qMin<int>(maxlen - readBytes, d->readBuffer.nextDataBlockSize());
+ ::memcpy(data + readBytes, readPtr, bytesToRead);
+ readBytes += bytesToRead;
+ d->readBuffer.free(bytesToRead);
+ } while (!d->readBuffer.isEmpty() && readBytes < maxlen);
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::readData(" << (void *)data << "," << maxlen << ") ==" << readBytes;
+#endif
+ return readBytes;
+}
+
+/*!
+ \reimp
+*/
+qint64 QSslSocket::writeData(const char *data, qint64 len)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::writeData(" << (void *)data << "," << len << ")";
+#endif
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return d->plainSocket->write(data, len);
+
+ char *writePtr = d->writeBuffer.reserve(len);
+ ::memcpy(writePtr, data, len);
+
+ // make sure we flush to the plain socket's buffer
+ QMetaObject::invokeMethod(this, "_q_flushWriteBuffer", Qt::QueuedConnection);
+
+ return len;
+}
+
+/*!
+ \internal
+*/
+QSslSocketPrivate::QSslSocketPrivate()
+ : initialized(false), readyReadEmittedPointer(0), plainSocket(0)
+{
+ QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+}
+
+/*!
+ \internal
+*/
+QSslSocketPrivate::~QSslSocketPrivate()
+{
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::init()
+{
+ mode = QSslSocket::UnencryptedMode;
+ autoStartHandshake = false;
+ connectionEncrypted = false;
+ ignoreSslErrors = false;
+
+ readBuffer.clear();
+ writeBuffer.clear();
+ configuration.peerCertificate.clear();
+ configuration.peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> QSslSocketPrivate::defaultCiphers()
+{
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->config->ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> QSslSocketPrivate::supportedCiphers()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->supportedCiphers;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->ciphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->supportedCiphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCertificate> QSslSocketPrivate::defaultCaCertificates()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->config->caCertificates;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates = certs;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QList<QSslCertificate> certs = QSslCertificate::fromPath(path, format, syntax);
+ if (certs.isEmpty())
+ return false;
+
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += certs;
+ return true;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::addDefaultCaCertificate(const QSslCertificate &cert)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += cert;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::addDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += certs;
+}
+
+/*!
+ \internal
+*/
+QSslConfiguration QSslConfigurationPrivate::defaultConfiguration()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return QSslConfiguration(globalData()->config.data());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::setDefaultConfiguration(const QSslConfiguration &configuration)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ if (globalData()->config == configuration.d)
+ return; // nothing to do
+
+ globalData()->config = const_cast<QSslConfigurationPrivate*>(configuration.d.constData());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPrivate *ptr)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ const QSslConfigurationPrivate *global = globalData()->config.constData();
+
+ ptr->ref = 1;
+ ptr->peerCertificate = global->peerCertificate;
+ ptr->peerCertificateChain = global->peerCertificateChain;
+ ptr->localCertificate = global->localCertificate;
+ ptr->privateKey = global->privateKey;
+ ptr->sessionCipher = global->sessionCipher;
+ ptr->ciphers = global->ciphers;
+ ptr->caCertificates = global->caCertificates;
+ ptr->protocol = global->protocol;
+ ptr->peerVerifyMode = global->peerVerifyMode;
+ ptr->peerVerifyDepth = global->peerVerifyDepth;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode)
+{
+ Q_Q(QSslSocket);
+ q->setOpenMode(openMode); // <- from QIODevice
+ q->setSocketState(QAbstractSocket::UnconnectedState);
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ q->setLocalPort(0);
+ q->setLocalAddress(QHostAddress());
+ q->setPeerPort(0);
+ q->setPeerAddress(QHostAddress());
+ q->setPeerName(QString());
+
+ plainSocket = new QTcpSocket(q);
+ q->connect(plainSocket, SIGNAL(connected()),
+ q, SLOT(_q_connectedSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(hostFound()),
+ q, SLOT(_q_hostFoundSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(disconnected()),
+ q, SLOT(_q_disconnectedSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ q, SLOT(_q_stateChangedSlot(QAbstractSocket::SocketState)),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ q, SLOT(_q_errorSlot(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(readyRead()),
+ q, SLOT(_q_readyReadSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(bytesWritten(qint64)),
+ q, SLOT(_q_bytesWrittenSlot(qint64)),
+ Qt::DirectConnection);
+#ifndef QT_NO_NETWORKPROXY
+ q->connect(plainSocket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ q, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+#endif
+
+ readBuffer.clear();
+ writeBuffer.clear();
+ connectionEncrypted = false;
+ configuration.peerCertificate.clear();
+ configuration.peerCertificateChain.clear();
+ mode = QSslSocket::UnencryptedMode;
+ q->setReadBufferSize(readBufferMaxSize);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_connectedSlot()
+{
+ Q_Q(QSslSocket);
+ q->setLocalPort(plainSocket->localPort());
+ q->setLocalAddress(plainSocket->localAddress());
+ q->setPeerPort(plainSocket->peerPort());
+ q->setPeerAddress(plainSocket->peerAddress());
+ q->setPeerName(plainSocket->peerName());
+ cachedSocketDescriptor = plainSocket->socketDescriptor();
+
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_connectedSlot()";
+ qDebug() << "\tstate =" << q->state();
+ qDebug() << "\tpeer =" << q->peerName() << q->peerAddress() << q->peerPort();
+ qDebug() << "\tlocal =" << QHostInfo::fromName(q->localAddress().toString()).hostName()
+ << q->localAddress() << q->localPort();
+#endif
+ emit q->connected();
+
+ if (autoStartHandshake) {
+ q->startClientEncryption();
+ } else if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_hostFoundSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_hostFoundSlot()";
+ qDebug() << "\tstate =" << q->state();
+#endif
+ emit q->hostFound();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_disconnectedSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_disconnectedSlot()";
+ qDebug() << "\tstate =" << q->state();
+#endif
+ disconnected();
+ emit q->disconnected();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_stateChangedSlot(QAbstractSocket::SocketState state)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ")";
+#endif
+ q->setSocketState(state);
+ emit q->stateChanged(state);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_errorSlot(" << error << ")";
+ qDebug() << "\tstate =" << q->state();
+ qDebug() << "\terrorString =" << q->errorString();
+#endif
+ q->setSocketError(plainSocket->error());
+ q->setErrorString(plainSocket->errorString());
+ emit q->error(error);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_readyReadSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_readyReadSlot() -" << plainSocket->bytesAvailable() << "bytes available";
+#endif
+ if (mode == QSslSocket::UnencryptedMode) {
+ if (readyReadEmittedPointer)
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ return;
+ }
+
+ transmit();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_bytesWrittenSlot(qint64 written)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ")";
+#endif
+
+ if (mode == QSslSocket::UnencryptedMode)
+ emit q->bytesWritten(written);
+ else
+ emit q->encryptedBytesWritten(written);
+ if (state == QAbstractSocket::ClosingState && writeBuffer.isEmpty())
+ q->disconnectFromHost();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_flushWriteBuffer()
+{
+ Q_Q(QSslSocket);
+ if (!writeBuffer.isEmpty())
+ q->flush();
+}
+
+QT_END_NAMESPACE
+
+// For private slots
+#define d d_ptr
+#include "moc_qsslsocket.cpp"