/*!
\internal
*/
-QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName, QWebSocketServerPrivate::SecureMode secureMode,
- QWebSocketServer * const pWebSocketServer, QObject *parent) :
- QObject(parent),
+QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
+ QWebSocketServerPrivate::SslMode secureMode,
+ QWebSocketServer * const pWebSocketServer) :
+ QObjectPrivate(),
q_ptr(pWebSocketServer),
m_pTcpServer(Q_NULLPTR),
m_serverName(serverName),
m_secureMode(secureMode),
- m_pendingConnections()
+ m_pendingConnections(),
+ m_error(QWebSocketProtocol::CloseCodeNormal),
+ m_errorString()
{
Q_ASSERT(pWebSocketServer);
- if (m_secureMode == NON_SECURE_MODE)
- {
- m_pTcpServer = new QTcpServer(this);
- connect(m_pTcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
- }
- else
- {
+}
+
+/*!
+ \internal
+ */
+void QWebSocketServerPrivate::init()
+{
+ if (m_secureMode == NonSecureMode) {
+ m_pTcpServer = new QTcpServer();
+ if (Q_LIKELY(m_pTcpServer))
+ QObjectPrivate::connect(m_pTcpServer, &QTcpServer::newConnection,
+ this, &QWebSocketServerPrivate::onNewConnection);
+ else
+ qFatal("Could not allocate memory for tcp server.");
+ } else {
#ifndef QT_NO_SSL
- QSslServer *pSslServer = new QSslServer(this);
+ QSslServer *pSslServer = new QSslServer();
m_pTcpServer = pSslServer;
- connect(pSslServer, SIGNAL(newEncryptedConnection()), this, SLOT(onNewConnection()));
- connect(pSslServer, SIGNAL(peerVerifyError(QSslError)), q_ptr, SIGNAL(peerVerifyError(QSslError)));
- connect(pSslServer, SIGNAL(sslErrors(QList<QSslError>)), q_ptr, SIGNAL(sslErrors(QList<QSslError>)));
+ if (Q_LIKELY(m_pTcpServer)) {
+ QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
+ this, &QWebSocketServerPrivate::onNewConnection);
+ QObject::connect(pSslServer, &QSslServer::peerVerifyError,
+ q_ptr, &QWebSocketServer::peerVerifyError);
+ QObject::connect(pSslServer, &QSslServer::sslErrors,
+ q_ptr, &QWebSocketServer::sslErrors);
+ }
+#else
+ qFatal("SSL not supported on this platform.");
#endif
}
- connect(m_pTcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), q_ptr, SIGNAL(acceptError(QAbstractSocket::SocketError)));
+ QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError);
}
/*!
*/
QWebSocketServerPrivate::~QWebSocketServerPrivate()
{
- while (!m_pendingConnections.isEmpty())
- {
- QWebSocket *pWebSocket = m_pendingConnections.dequeue();
- pWebSocket->close(QWebSocketProtocol::CC_GOING_AWAY, tr("Server closed."));
- pWebSocket->deleteLater();
- }
+ close();
m_pTcpServer->deleteLater();
}
*/
void QWebSocketServerPrivate::close()
{
+ Q_Q(QWebSocketServer);
m_pTcpServer->close();
+ while (!m_pendingConnections.isEmpty()) {
+ QWebSocket *pWebSocket = m_pendingConnections.dequeue();
+ pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway,
+ QWebSocketServer::tr("Server closed."));
+ pWebSocket->deleteLater();
+ }
+ //emit signal via the event queue, so the server gets time
+ //to process any hanging events, like flushing buffers aso
+ QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
}
/*!
*/
QString QWebSocketServerPrivate::errorString() const
{
- return m_pTcpServer->errorString();
+ if (m_errorString.isEmpty())
+ return m_pTcpServer->errorString();
+ else
+ return m_errorString;
}
/*!
*/
bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
{
- return m_pTcpServer->listen(address, port);
+ bool success = m_pTcpServer->listen(address, port);
+ if (!success)
+ setErrorFromSocketError(m_pTcpServer->serverError(), m_pTcpServer->errorString());
+ return success;
}
/*!
void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
{
if (m_pendingConnections.size() < maxPendingConnections())
- {
m_pendingConnections.enqueue(pWebSocket);
- }
+}
+
+/*!
+ \internal
+ */
+void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
+ const QString &errorDescription)
+{
+ Q_UNUSED(error);
+ setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
}
/*!
QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
{
QWebSocket *pWebSocket = Q_NULLPTR;
- if (!m_pendingConnections.isEmpty())
- {
+ if (Q_LIKELY(!m_pendingConnections.isEmpty()))
pWebSocket = m_pendingConnections.dequeue();
- }
return pWebSocket;
}
/*!
\internal
*/
-QAbstractSocket::SocketError QWebSocketServerPrivate::serverError() const
+QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
{
- return m_pTcpServer->serverError();
+ return m_error;
}
/*!
/*!
\internal
*/
-bool QWebSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut)
-{
- return m_pTcpServer->waitForNewConnection(msec, timedOut);
-}
-
-/*!
- \internal
- */
QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
{
QList<QWebSocketProtocol::Version> supportedVersions;
/*!
\internal
*/
-QList<QString> QWebSocketServerPrivate::supportedProtocols() const
+QStringList QWebSocketServerPrivate::supportedProtocols() const
{
- QList<QString> supportedProtocols;
+ QStringList supportedProtocols;
return supportedProtocols; //no protocols are currently supported
}
/*!
\internal
*/
-QList<QString> QWebSocketServerPrivate::supportedExtensions() const
+QStringList QWebSocketServerPrivate::supportedExtensions() const
{
- QList<QString> supportedExtensions;
+ QStringList supportedExtensions;
return supportedExtensions; //no extensions are currently supported
}
*/
void QWebSocketServerPrivate::setServerName(const QString &serverName)
{
- m_serverName = serverName;
+ if (m_serverName != serverName)
+ m_serverName = serverName;
}
/*!
/*!
\internal
*/
-QWebSocketServerPrivate::SecureMode QWebSocketServerPrivate::secureMode() const
+QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
{
return m_secureMode;
}
#ifndef QT_NO_SSL
void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
{
- if (m_secureMode == SECURE_MODE)
- {
+ if (m_secureMode == SecureMode)
qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
- }
}
QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
{
- if (m_secureMode == SECURE_MODE)
- {
+ if (m_secureMode == SecureMode)
return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
- }
else
- {
return QSslConfiguration::defaultConfiguration();
- }
}
#endif
+void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
+{
+ if ((m_error != code) || (m_errorString != errorString)) {
+ Q_Q(QWebSocketServer);
+ m_error = code;
+ m_errorString = errorString;
+ Q_EMIT q->serverError(code);
+ }
+}
+
/*!
\internal
*/
void QWebSocketServerPrivate::onNewConnection()
{
QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
- connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(handshakeReceived()));
+ QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
+ this, &QWebSocketServerPrivate::handshakeReceived);
}
/*!
*/
void QWebSocketServerPrivate::onCloseConnection()
{
- QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
- if (pTcpSocket)
- {
- pTcpSocket->close();
+ if (Q_LIKELY(currentSender)) {
+ QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
+ if (Q_LIKELY(pTcpSocket))
+ pTcpSocket->close();
}
}
*/
void QWebSocketServerPrivate::handshakeReceived()
{
+ if (Q_UNLIKELY(!currentSender)) {
+ qWarning() << QWebSocketServer::tr("Sender is NULL. This is a Qt bug.");
+ return;
+ }
+ QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
+ if (Q_UNLIKELY(!pTcpSocket)) {
+ qWarning() << QWebSocketServer::tr("Sender is not a QTcpSocket. This is a Qt bug!!!");
+ return;
+ }
Q_Q(QWebSocketServer);
- QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
- if (pTcpSocket)
- {
- bool success = false;
- bool isSecure = false;
-
- disconnect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(handshakeReceived()));
-
- QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
- QTextStream textStream(pTcpSocket);
- textStream >> request;
-
- if (request.isValid())
- {
- QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
- Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
-
- QWebSocketHandshakeResponse response(request,
- m_serverName,
- corsAuthenticator.allowed(),
- supportedVersions(),
- supportedProtocols(),
- supportedExtensions());
-
- if (response.isValid())
- {
- QTextStream httpStream(pTcpSocket);
- httpStream << response;
- httpStream.flush();
-
- if (response.canUpgrade())
- {
- QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket, request, response);
- if (pWebSocket)
- {
- pWebSocket->setParent(this);
- addPendingConnection(pWebSocket);
- Q_EMIT q->newConnection();
- success = true;
- }
- else
- {
- //TODO: should set or emit error
- qDebug() << tr("Upgrading to websocket failed.");
- }
- }
- else
- {
- //TODO: should set or emit error
- qDebug() << tr("Cannot upgrade to websocket.");
+ bool success = false;
+ bool isSecure = false;
+
+ disconnect(pTcpSocket, &QTcpSocket::readyRead,
+ this, &QWebSocketServerPrivate::handshakeReceived);
+
+ if (m_pendingConnections.length() >= maxPendingConnections()) {
+ pTcpSocket->close();
+ pTcpSocket->deleteLater();
+ qWarning() << QWebSocketServer::tr("Too many pending connections: " \
+ "New websocket connection not accepted.");
+ setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+ QWebSocketServer::tr("Too many pending connections."));
+ return;
+ }
+
+ QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
+ QTextStream textStream(pTcpSocket);
+ request.readHandshake(textStream);
+
+ if (request.isValid()) {
+ QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
+ Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);
+
+ QWebSocketHandshakeResponse response(request,
+ m_serverName,
+ corsAuthenticator.allowed(),
+ supportedVersions(),
+ supportedProtocols(),
+ supportedExtensions());
+
+ if (response.isValid()) {
+ QTextStream httpStream(pTcpSocket);
+ httpStream << response;
+ httpStream.flush();
+
+ if (response.canUpgrade()) {
+ QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
+ request,
+ response);
+ if (pWebSocket) {
+ addPendingConnection(pWebSocket);
+ Q_EMIT q->newConnection();
+ success = true;
+ } else {
+ setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+ QWebSocketServer::tr("Upgrading to websocket failed."));
}
}
- else
- {
- //TODO: should set or emit error
- qDebug() << tr("Invalid response received.");
+ else {
+ setError(response.error(), response.errorString());
}
- }
- if (!success)
- {
- //TODO: should set or emit error
- qDebug() << tr("Closing socket because of invalid or unsupported request.");
- pTcpSocket->close();
+ } else {
+ setError(QWebSocketProtocol::CloseCodeProtocolError,
+ QWebSocketServer::tr("Invalid response received."));
}
}
- else
- {
- qWarning() << "Sender socket is NULL. This should not happen, otherwise it is a Qt bug!!!";
+ if (!success) {
+ qWarning() << QWebSocketServer::tr("Closing socket because of invalid or unsupported request.");
+ pTcpSocket->close();
}
}