Hi All,

I built an SSL server by subclassing the QTcpServer. The stress test I did is connecting and disconnecting from the server about 200,000 times (client connects and disconnects each 100ms). I can see that the memory consumption gets larger as the number of connections and drops increase.

My client application on the other hand doesn't have this phenomena.

I tested the server and client under Windows XP and Ubuntu 9.04.

Honestly I don't know if this is a QT issue or a bug in my application. But I will be happy if someone could guide me where the memory leak could be.

Please feel free to comment on my code as well.

Thank you in advance!

And here is the code:
Pay attention that the defines NO_AUTH_TIME_LIMIT and UNSECURE_CONNECTION are off!

sslserver.h:
Qt Code:
  1. #ifndef SSLSERVER_H
  2. #define SSLSERVER_H
  3.  
  4. #include <QTcpServer>
  5. #include <QSslSocket>
  6.  
  7. class SslServer : public QTcpServer
  8. {
  9. Q_OBJECT
  10. public:
  11. SslServer(QObject *parent=0);
  12. ~SslServer();
  13.  
  14. protected:
  15. void incomingConnection(int socketDescriptor);
  16.  
  17. private slots:
  18. void error(QAbstractSocket::SocketError err);
  19. };
  20. #endif // SSLSERVER_H
To copy to clipboard, switch view to plain text mode 


sslserver.c:
Qt Code:
  1. #include "sslserver.h"
  2. #include "messagethread.h"
  3.  
  4. SslServer::SslServer(QObject *parent):QTcpServer(parent)
  5. {
  6. }
  7.  
  8. SslServer::~SslServer()
  9. {
  10. }
  11.  
  12. void SslServer::incomingConnection(int socketDescriptor)
  13. {
  14. MessageThread *thread = new MessageThread(socketDescriptor, this);
  15. connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
  16. thread->start();
  17. }
  18. void SslServer::error(QAbstractSocket::SocketError err)
  19. {
  20. qDebug()<<tr("Error: %1").arg(err);
  21. }
To copy to clipboard, switch view to plain text mode 


messagethread.h:
Qt Code:
  1. #ifndef MESSAGETHREAD_H
  2. #define MESSAGETHREAD_H
  3.  
  4. #include <QThread>
  5. #include <QSslSocket>
  6. #include <QAbstractSocket>
  7. #include <QTimer>
  8. #include <QMutex>
  9.  
  10. #define THREAD_MAX_PENDING_CONN_INTERVAL (2000)
  11.  
  12. class MessageThread : public QThread
  13. {
  14. Q_OBJECT
  15. public:
  16. MessageThread(int socketDescriptor, QObject *parent = 0);
  17. ~MessageThread();
  18.  
  19. protected:
  20. void run(void);
  21.  
  22. private:
  23. int m_socketDescriptor; // Socket descriptor of the connection
  24. quint16 m_numOfExpectedBytes; // Number of expected bytes from the client
  25. quint32 m_currentUserId; // Current user ID
  26. bool m_cleanExitDone; // Indicates that an exit procedure was done
  27. QMutex *m_mutex; // Mutex to perform clean exit without interrupts
  28.  
  29. #ifdef UNSECURE_CONNECTION // Define m_socket to be SSL or TCP socket
  30. QTcpSocket *m_socket;
  31. #else
  32. QSslSocket *m_socket;
  33. #endif
  34.  
  35. #ifndef NO_AUTH_TIME_LIMIT // If NO_AUTH_TIME_LIMIT is NOT present, the server will reject an unauthorized
  36. QTimer *m_authTimer; // connection which is held for a defined time frame
  37. bool m_authorized;
  38. #endif
  39.  
  40. private slots:
  41. void processReadyRead(void);
  42. void checkPending(void);
  43. void performCleanExit(void);
  44. };
  45.  
  46. #endif // MESSAGETHREAD_H
To copy to clipboard, switch view to plain text mode 


messagethread.c:
Qt Code:
  1. #include "messagethread.h"
  2. #include <QIODevice>
  3. #include <QDataStream>
  4. #include <QAbstractSocket>
  5. #include <QFile>
  6. #include <QCoreApplication>
  7. #include <QDebug>
  8.  
  9. MessageThread::MessageThread(int socketDescriptor, QObject *parent):QThread(parent)
  10. {
  11. m_socketDescriptor = socketDescriptor;
  12. m_numOfExpectedBytes = 0;
  13. m_cleanExitDone = false;
  14. m_mutex = new QMutex();
  15. }
  16.  
  17. MessageThread::~MessageThread()
  18. {
  19. delete m_mutex;
  20. }
  21.  
  22. void MessageThread::run(void)
  23. {
  24. #ifdef UNSECURE_CONNECTION
  25. m_socket = new QTcpSocket();
  26. #else
  27. m_socket = new QSslSocket();
  28. #endif
  29. if (m_socket->setSocketDescriptor(m_socketDescriptor))
  30. {
  31. QList<QSslCertificate> certificateList;
  32. certificateList.append(QSslCertificate());
  33. connect(m_socket, SIGNAL(readyRead()), this, SLOT(processReadyRead()), Qt::DirectConnection);
  34. connect(m_socket, SIGNAL(disconnected()), this, SLOT(performCleanExit()));
  35. #ifdef UNSECURE_CONNECTION
  36. // Nothing to do if the connection is unsecure
  37. #else
  38. // Add the key that will make the handshake
  39. m_socket->setPrivateKey(":/certs/my-key.pem");
  40. m_socket->setLocalCertificate(":/certs/my-cert.pem");
  41.  
  42. // Add the certificate authority to the list of certificate sent
  43. QFile f(":/certs/cacert.pem");
  44. f.open(QIODevice::ReadOnly);
  45. QSslCertificate cert(f.readAll());
  46. if (!cert.isValid())
  47. qDebug("Invaild certificate");
  48. m_socket->addCaCertificate(cert);
  49. m_socket->startServerEncryption();
  50. #endif
  51. }
  52. else
  53. {
  54. qDebug()<<tr("Could not create socket from descriptor");
  55. qDebug()<<m_socket->errorString();
  56. performCleanExit();
  57. }
  58. #ifndef NO_AUTH_TIME_LIMIT
  59. m_authorized = false;
  60. m_authTimer = new QTimer();
  61. connect(m_authTimer, SIGNAL(timeout()), this, SLOT(checkPending()), Qt::DirectConnection);
  62. m_authTimer->setInterval(THREAD_MAX_PENDING_CONN_INTERVAL);
  63. m_authTimer->setSingleShot(true);
  64. m_authTimer->start();
  65. #endif
  66. /* Call the event loop of the thread */
  67. exec();
  68. }
  69.  
  70. void MessageThread::performCleanExit(void)
  71. {
  72. m_mutex->lock();
  73. if (!m_cleanExitDone)
  74. {
  75. QAbstractSocket::SocketState s;
  76. m_cleanExitDone = true;
  77. s = m_socket->state();
  78. // Remove the connection
  79. if (s != QAbstractSocket::UnconnectedState && s != QAbstractSocket::ClosingState)
  80. {
  81. m_socket->disconnectFromHost();
  82. m_socket->waitForDisconnected();
  83. }
  84. disconnect(m_socket, 0, 0, 0);
  85. m_socket->deleteLater();
  86. }
  87. #ifndef NO_AUTH_TIME_LIMIT
  88. m_authTimer->deleteLater();
  89. #endif
  90. m_mutex->unlock();
  91. // Cover the case where we started with this function and the check pending
  92. // is called right after quit().
  93. QCoreApplication::processEvents();
  94. quit();
  95. }
  96.  
  97.  
  98. void MessageThread::processReadyRead(void)
  99. {
  100. if (m_socket->bytesAvailable() == 0)
  101. {
  102. return;
  103. }
  104. m_socket->readAll();
  105. //performCleanExit();
  106. }
  107.  
  108. void MessageThread::checkPending(void)
  109. {
  110. #ifndef NO_AUTH_TIME_LIMIT
  111. if (!m_authorized)
  112. {
  113. qDebug("Time out baby");
  114. performCleanExit();
  115. }
  116. #endif
  117. }
To copy to clipboard, switch view to plain text mode