1 /****************************************************************************
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtWebSockets module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qwebsocketserver.h"
43 #include "qwebsocketserver_p.h"
45 #include "qsslserver_p.h"
47 #include "qwebsocketprotocol.h"
48 #include "qwebsockethandshakerequest_p.h"
49 #include "qwebsockethandshakeresponse_p.h"
50 #include "qwebsocket.h"
51 #include "qwebsocket_p.h"
52 #include "qwebsocketcorsauthenticator.h"
54 #include <QtNetwork/QTcpServer>
55 #include <QtNetwork/QTcpSocket>
56 #include <QtNetwork/QNetworkProxy>
63 QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
64 QWebSocketServerPrivate::SslMode secureMode,
65 QWebSocketServer * const pWebSocketServer) :
67 q_ptr(pWebSocketServer),
68 m_pTcpServer(Q_NULLPTR),
69 m_serverName(serverName),
70 m_secureMode(secureMode),
71 m_pendingConnections(),
72 m_error(QWebSocketProtocol::CloseCodeNormal),
75 Q_ASSERT(pWebSocketServer);
81 void QWebSocketServerPrivate::init()
83 if (m_secureMode == NonSecureMode) {
84 m_pTcpServer = new QTcpServer();
85 if (Q_LIKELY(m_pTcpServer))
86 QObjectPrivate::connect(m_pTcpServer, &QTcpServer::newConnection,
87 this, &QWebSocketServerPrivate::onNewConnection);
89 qFatal("Could not allocate memory for tcp server.");
92 QSslServer *pSslServer = new QSslServer();
93 m_pTcpServer = pSslServer;
94 if (Q_LIKELY(m_pTcpServer)) {
95 QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
96 this, &QWebSocketServerPrivate::onNewConnection);
97 QObject::connect(pSslServer, &QSslServer::peerVerifyError,
98 q_ptr, &QWebSocketServer::peerVerifyError);
99 QObject::connect(pSslServer, &QSslServer::sslErrors,
100 q_ptr, &QWebSocketServer::sslErrors);
103 qFatal("SSL not supported on this platform.");
106 QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError);
112 QWebSocketServerPrivate::~QWebSocketServerPrivate()
115 m_pTcpServer->deleteLater();
121 void QWebSocketServerPrivate::close(bool aboutToDestroy)
123 Q_Q(QWebSocketServer);
124 m_pTcpServer->close();
125 while (!m_pendingConnections.isEmpty()) {
126 QWebSocket *pWebSocket = m_pendingConnections.dequeue();
127 pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway,
128 QWebSocketServer::tr("Server closed."));
129 pWebSocket->deleteLater();
131 if (!aboutToDestroy) {
132 //emit signal via the event queue, so the server gets time
133 //to process any hanging events, like flushing buffers aso
134 QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
141 QString QWebSocketServerPrivate::errorString() const
143 if (m_errorString.isEmpty())
144 return m_pTcpServer->errorString();
146 return m_errorString;
152 bool QWebSocketServerPrivate::hasPendingConnections() const
154 return !m_pendingConnections.isEmpty();
160 bool QWebSocketServerPrivate::isListening() const
162 return m_pTcpServer->isListening();
168 bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
170 bool success = m_pTcpServer->listen(address, port);
172 setErrorFromSocketError(m_pTcpServer->serverError(), m_pTcpServer->errorString());
179 int QWebSocketServerPrivate::maxPendingConnections() const
181 return m_pTcpServer->maxPendingConnections();
187 void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
189 if (m_pendingConnections.size() < maxPendingConnections())
190 m_pendingConnections.enqueue(pWebSocket);
196 void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
197 const QString &errorDescription)
200 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
206 QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
208 QWebSocket *pWebSocket = Q_NULLPTR;
209 if (Q_LIKELY(!m_pendingConnections.isEmpty()))
210 pWebSocket = m_pendingConnections.dequeue();
217 void QWebSocketServerPrivate::pauseAccepting()
219 m_pTcpServer->pauseAccepting();
222 #ifndef QT_NO_NETWORKPROXY
226 QNetworkProxy QWebSocketServerPrivate::proxy() const
228 return m_pTcpServer->proxy();
234 void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
236 m_pTcpServer->setProxy(networkProxy);
242 void QWebSocketServerPrivate::resumeAccepting()
244 m_pTcpServer->resumeAccepting();
250 QHostAddress QWebSocketServerPrivate::serverAddress() const
252 return m_pTcpServer->serverAddress();
258 QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
266 quint16 QWebSocketServerPrivate::serverPort() const
268 return m_pTcpServer->serverPort();
274 void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
276 m_pTcpServer->setMaxPendingConnections(numConnections);
282 bool QWebSocketServerPrivate::setSocketDescriptor(qintptr socketDescriptor)
284 return m_pTcpServer->setSocketDescriptor(socketDescriptor);
290 qintptr QWebSocketServerPrivate::socketDescriptor() const
292 return m_pTcpServer->socketDescriptor();
298 QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
300 QList<QWebSocketProtocol::Version> supportedVersions;
301 supportedVersions << QWebSocketProtocol::currentVersion(); //we only support V13
302 return supportedVersions;
308 QStringList QWebSocketServerPrivate::supportedProtocols() const
310 QStringList supportedProtocols;
311 return supportedProtocols; //no protocols are currently supported
317 QStringList QWebSocketServerPrivate::supportedExtensions() const
319 QStringList supportedExtensions;
320 return supportedExtensions; //no extensions are currently supported
326 void QWebSocketServerPrivate::setServerName(const QString &serverName)
328 if (m_serverName != serverName)
329 m_serverName = serverName;
335 QString QWebSocketServerPrivate::serverName() const
343 QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
349 void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
351 if (m_secureMode == SecureMode)
352 qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
355 QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
357 if (m_secureMode == SecureMode)
358 return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
360 return QSslConfiguration::defaultConfiguration();
364 void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
366 if ((m_error != code) || (m_errorString != errorString)) {
367 Q_Q(QWebSocketServer);
369 m_errorString = errorString;
370 Q_EMIT q->serverError(code);
377 void QWebSocketServerPrivate::onNewConnection()
379 QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
380 QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
381 this, &QWebSocketServerPrivate::handshakeReceived);
387 void QWebSocketServerPrivate::onCloseConnection()
389 if (Q_LIKELY(currentSender)) {
390 QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
391 if (Q_LIKELY(pTcpSocket))
399 void QWebSocketServerPrivate::handshakeReceived()
401 if (Q_UNLIKELY(!currentSender)) {
402 qWarning() << QWebSocketServer::tr("Sender is NULL. This is a Qt bug.");
405 QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
406 if (Q_UNLIKELY(!pTcpSocket)) {
407 qWarning() << QWebSocketServer::tr("Sender is not a QTcpSocket. This is a Qt bug!!!");
410 Q_Q(QWebSocketServer);
411 bool success = false;
412 bool isSecure = false;
414 disconnect(pTcpSocket, &QTcpSocket::readyRead,
415 this, &QWebSocketServerPrivate::handshakeReceived);
417 if (m_pendingConnections.length() >= maxPendingConnections()) {
419 pTcpSocket->deleteLater();
420 qWarning() << QWebSocketServer::tr("Too many pending connections: " \
421 "New websocket connection not accepted.");
422 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
423 QWebSocketServer::tr("Too many pending connections."));
427 QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
428 QTextStream textStream(pTcpSocket);
429 request.readHandshake(textStream);
431 if (request.isValid()) {
432 QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
433 Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
435 QWebSocketHandshakeResponse response(request,
437 corsAuthenticator.allowed(),
439 supportedProtocols(),
440 supportedExtensions());
442 if (response.isValid()) {
443 QTextStream httpStream(pTcpSocket);
444 httpStream << response;
447 if (response.canUpgrade()) {
448 QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
452 addPendingConnection(pWebSocket);
453 Q_EMIT q->newConnection();
456 setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
457 QWebSocketServer::tr("Upgrading to websocket failed."));
461 setError(response.error(), response.errorString());
464 setError(QWebSocketProtocol::CloseCodeProtocolError,
465 QWebSocketServer::tr("Invalid response received."));
469 qWarning() << QWebSocketServer::tr("Closing socket because of invalid or unsupported request.");