QSslServer: Make sure maxPendingConnections applies to all sockets

Not just the ones we added to the pending sockets list

Pick-to: 6.4
Change-Id: I0a0016fe39df7ca2fc3f0c4e4111195bc6d90198
Reviewed-by: Konrad Kujawa <konrad.kujawa@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Mårten Nordheim 2022-08-16 15:51:10 +02:00
parent 29a1fe72a0
commit 1ee75e4740
5 changed files with 52 additions and 1 deletions

View File

@ -172,7 +172,7 @@ void QTcpServerPrivate::readNotification()
{
Q_Q(QTcpServer);
for (;;) {
if (pendingConnections.count() >= maxConnections) {
if (totalPendingConnections() >= maxConnections) {
#if defined (QTCPSERVER_DEBUG)
qDebug("QTcpServerPrivate::_q_processIncomingConnection() too many connections");
#endif
@ -205,6 +205,20 @@ void QTcpServerPrivate::readNotification()
}
}
/*!
\internal
Return the amount of sockets currently in queue for the server.
This is to make maxPendingConnections work properly with servers that don't
necessarily have 'ready-to-go' sockets as soon as they connect,
e.g. QSslServer.
By default we just return pendingConnections.size(), which is equivalent to
what it did before.
*/
int QTcpServerPrivate::totalPendingConnections() const
{
return int(pendingConnections.size());
}
/*!
Constructs a QTcpServer object.

View File

@ -56,6 +56,7 @@ public:
#endif
virtual void configureCreatedSocket();
virtual int totalPendingConnections() const;
// from QAbstractSocketEngineReceiver
void readNotification() override;

View File

@ -350,6 +350,12 @@ void QSslServerPrivate::removeSocketData(quintptr socket)
}
}
int QSslServerPrivate::totalPendingConnections() const
{
// max pending connections is int, so this cannot exceed that
return QTcpServerPrivate::totalPendingConnections() + int(socketData.size());
}
void QSslServerPrivate::checkClientHelloAndContinue()
{
Q_Q(QSslServer);

View File

@ -38,6 +38,7 @@ public:
void initializeHandshakeProcess(QSslSocket *socket);
void removeSocketData(quintptr socket);
void handleHandshakeTimedOut(QSslSocket *socket);
int totalPendingConnections() const override;
struct SocketData {
QMetaObject::Connection readyReadConnection;

View File

@ -25,6 +25,7 @@ private slots:
#endif
void plaintextClient();
void quietClient();
void manyQuietClients();
private:
QString testDataDir;
@ -487,6 +488,34 @@ void tst_QSslServer::quietClient()
QCOMPARE(serverPeerPort, clientLocalPort);
}
void tst_QSslServer::manyQuietClients()
{
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
constexpr qsizetype ExpectedConnections = 5;
server.server.setMaxPendingConnections(ExpectedConnections);
QVERIFY(server.server.listen());
// Connect one socket encrypted so we have a socket in the regular queue
QSslSocket tlsSocket;
QObject::connect(&tlsSocket, &QSslSocket::sslErrors, &tlsSocket,
qOverload<const QList<QSslError> &>(&QSslSocket::ignoreSslErrors));
tlsSocket.connectToHostEncrypted("127.0.0.1", server.server.serverPort());
// Then we connect a bunch of TCP sockets who will not send any data at all
std::array<QTcpSocket, size_t(ExpectedConnections) * 4> sockets;
for (QTcpSocket &socket : sockets)
socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort());
QTest::qWait(500); // some leeway to let connections try to connect...
// I happen to know the sockets are all children of the server, so let's see
// how many are created:
qsizetype connectedCount = server.server.findChildren<QSslSocket *>().size();
QCOMPARE(connectedCount, ExpectedConnections);
// 1 socket is ready and pending
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1);
}
QTEST_MAIN(tst_QSslServer)
#include "tst_qsslserver.moc"