Results 1 to 6 of 6

Thread: A Web Proxy multithread

  1. #1
    Join Date
    May 2008
    Posts
    276
    Thanks
    13
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default A Web Proxy multithread

    I found within the Web a good example to implement an Http Proxy.
    It works great, but the problem is that it is single threaded.
    I tried to change it to a multithread version, but for some odd reason the code fires a segfault.
    The original single thread version follows:
    Qt Code:
    1. /*
    2.  
    3. */
    4.  
    5. #include "webproxy.h"
    6. #include <QtNetwork>
    7. #include <QMessageBox>
    8. #include <QtGui>
    9. #include <QHash>
    10.  
    11.  
    12. WebProxy::WebProxy(QObject *parent,int port): QObject(parent)
    13.  
    14. {
    15.  
    16. QTcpServer *proxyServer = new QTcpServer(this);
    17. if (!proxyServer->listen(QHostAddress::Any, port)) {
    18. emit error(1);
    19.  
    20. return;
    21. }
    22.  
    23. connect(proxyServer, SIGNAL(newConnection()), this, SLOT(manageQuery()));
    24. qDebug() << "Proxy server running at port" << proxyServer->serverPort();
    25.  
    26.  
    27. }
    28.  
    29. void WebProxy::setAddress(const QHostAddress &a, int port)
    30. {
    31. proxyAddress = a;
    32. proxyPort = port;
    33. port = port < 0 ? 8081 : port;
    34.  
    35.  
    36. }
    37.  
    38. void WebProxy::manageQuery() {
    39. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender());
    40. QTcpSocket *socket = proxyServer->nextPendingConnection();
    41. connect(socket, SIGNAL(readyRead()), this, SLOT(processQuery()));
    42. connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    43. qDebug()<<"New connection started..."<<socket->peerAddress();
    44. }
    45. QUrl WebProxy::getUrl(QList<QByteArray > &entries)
    46. {
    47.  
    48. QByteArray method = entries.value(0);
    49. QByteArray address = entries.value(1);
    50. QByteArray version = entries.value(2);
    51.  
    52.  
    53. QUrl url = QUrl::fromEncoded(address);
    54. if (!url.isValid()) {
    55.  
    56. qWarning() << "Invalid URL:" << url;
    57. return QString();
    58. }
    59. return url;
    60. }
    61.  
    62. void WebProxy::processQuery() {
    63.  
    64. QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
    65. QByteArray requestData = socket->readAll();
    66.  
    67. int pos = requestData.indexOf("\r\n");
    68.  
    69. QByteArray requestLine = requestData.left(pos);
    70. requestData.remove(0, pos + 2);
    71.  
    72. QList<QByteArray> entries = requestLine.split(' ');
    73. QByteArray method = entries.value(0);
    74. QByteArray address = entries.value(1);
    75. QByteArray version = entries.value(2);
    76.  
    77. QByteArray auth;
    78. QByteArray authMethod;
    79.  
    80. QUrl url = QUrl::fromEncoded(address);
    81. if (!url.isValid()) {
    82. qWarning() << "Invalid URL:" << url;
    83. socket->disconnectFromHost();
    84. return;
    85. }
    86.  
    87. QString host = url.host();
    88.  
    89. int port = (url.port() <= 0) ? 80 : url.port();
    90. QByteArray req = url.encodedPath();
    91. if (url.hasQuery())
    92. req.append('?').append(url.encodedQuery());
    93.  
    94. requestLine = method + " " + req + " " + version + "\r\n";
    95.  
    96.  
    97. QString key = host + ':' + QString::number(port);
    98. QTcpSocket *proxySocket = socket->findChild<QTcpSocket*>(key);
    99. if (proxySocket) {
    100. proxySocket->setObjectName(key);
    101. proxySocket->setProperty("url", url);
    102. proxySocket->setProperty("requestData", requestData);
    103. proxySocket->write(requestData);
    104. } else {
    105. proxySocket = new QTcpSocket(socket);
    106. proxySocket->setObjectName(key);
    107. proxySocket->setProperty("url", url);
    108. proxySocket->setProperty("requestData", requestData);
    109. connect(proxySocket, SIGNAL(connected()), this, SLOT(sendRequest()));
    110. connect(proxySocket, SIGNAL(readyRead()), this, SLOT(transferData()));
    111. connect(proxySocket, SIGNAL(disconnected()), this, SLOT(closeConnection()));
    112. connect(proxySocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(closeConnection()));
    113. proxySocket->connectToHost(host, port);
    114. }
    115. }
    116.  
    117. void WebProxy::sendRequest() {
    118. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    119. QByteArray requestData = proxySocket->property("requestData").toByteArray();
    120. proxySocket->write(requestData);
    121. }
    122.  
    123. void WebProxy::transferData() {
    124.  
    125.  
    126. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    127. QByteArray data = proxySocket->readAll();
    128. QString host = proxySocket->peerAddress().toString();
    129.  
    130. QTcpSocket *socket = qobject_cast<QTcpSocket*>(proxySocket->parent());
    131. socket->write(data);
    132.  
    133. }
    134.  
    135. void WebProxy::closeConnection() {
    136. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    137. if (proxySocket) {
    138. QTcpSocket *socket = qobject_cast<QTcpSocket*>(proxySocket->parent());
    139. if (socket)
    140. socket->disconnectFromHost();
    141. if (proxySocket->error() != QTcpSocket::RemoteHostClosedError)
    142. qWarning() << "Error for:" << proxySocket->property("url").toUrl()
    143. << proxySocket->errorString();
    144. proxySocket->deleteLater();;
    145. }
    146. }
    To copy to clipboard, switch view to plain text mode 

    I call "new WebProxy " in the main.
    In the multithreaded version, I put all functions from manageQuery() inside a new threaded Class. But when a connection start, I got a segfault.
    Any help appreciated.
    Does anybody know

  2. #2
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: A Web Proxy multithread

    Quote Originally Posted by giusepped View Post
    In the multithreaded version, I put all functions from manageQuery() inside a new threaded Class. But when a connection start, I got a segfault.
    Any help appreciated.
    Please post the code that causes the problem.

  3. #3
    Join Date
    May 2008
    Posts
    276
    Thanks
    13
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: A Web Proxy multithread

    Ok, but it is as I said.
    Qt Code:
    1. WebProxy::WebProxy(QObject *parent,int port): QTcpServer(parent)
    2.  
    3. {
    4. qDebug()<<" Listen...";
    5. authMethod = "";
    6. proxyServer = new QTcpServer;
    7. if (!proxyServer->listen(QHostAddress::Any, port)) {
    8. emit error(1);
    9.  
    10. return;
    11. }
    12.  
    13. connect(proxyServer, SIGNAL(newConnection()), this, SLOT(go()));
    14. qDebug() << "Proxy server running at port" << proxyServer->serverPort() << proxyServer->serverAddress();
    15.  
    16. thr = 0;
    17. }
    18. void WebProxy::addFilter(const QHash<QString, QString> &user, const QHash<QString, QString> &pass, const QHash<QString, QString> &u_format, const QHash<QString, QString> &p_format, const QHash<QString, int> &dvr,const QHash<QString,QString > &submit, const QHash<QString,QString> &search)
    19. {
    20. qDebug() << "Server status..............";
    21. qDebug() << "Server status"<<proxyServer->isListening();
    22. hashUsername = user;
    23. hashPassword = pass;
    24. hashUFormat = u_format;
    25. hashPFormat = p_format;
    26. hashDvr = dvr;
    27. hashSubmit = submit;
    28. hashSearch = search;
    29.  
    30.  
    31. }
    32.  
    33. void WebProxy::setAddress(const QHostAddress &a, int port)
    34. {
    35. proxyAddress = a;
    36. proxyPort = port;
    37. port = port < 0 ? 8081 : port;
    38.  
    39.  
    40. }
    41. void WebProxy::go()
    42. {
    43. // Create a new Thread
    44. int sck = socketDescriptor();
    45. WebProxyThread *wpt = new WebProxyThread(sck,
    46. hashUsername,
    47. hashPassword,
    48. hashUFormat,
    49. hashPFormat,
    50. hashDvr,
    51. hashSubmit,
    52. hashSearch,this);
    53. connect(wpt, SIGNAL(finished()), wpt, SLOT(deleteLater()));
    54. wpt->start();
    55. qDebug() << "New thread"<<thr++;
    56.  
    57.  
    58. }
    To copy to clipboard, switch view to plain text mode 

    and the threaded proxy is in another class:
    Qt Code:
    1. #include "webproxythreaded.h"
    2. #include <QTcpServer>
    3. #include <QTcpSocket>
    4. #include <QtGui>
    5.  
    6.  
    7. WebProxyThread::WebProxyThread(int socketDescriptor,
    8. const QHash<QString, QString> &user,
    9. const QHash<QString, QString> &pass,
    10. const QHash<QString, QString> &u_format,
    11. const QHash<QString, QString> &p_format,
    12. const QHash<QString, int> &dvr,
    13. const QHash<QString, QString> &submit_str,
    14. const QHash<QString, QString> &submit_search,
    15. QObject *parent) :
    16. QThread(parent), socketDescriptor(socketDescriptor)
    17. {
    18. hashUsername = user;
    19. hashPassword = pass;
    20. hashUFormat = u_format;
    21. hashPFormat = p_format;
    22. hashDvr = dvr;
    23. hashSubmit = submit_str;
    24. hashSearch = submit_search;
    25. }
    26.  
    27.  
    28.  
    29.  
    30. void WebProxyThread::run()
    31. {
    32. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender());
    33. QTcpSocket *socket = proxyServer->nextPendingConnection();
    34. connect(socket, SIGNAL(readyRead()), this, SLOT(processQuery()));
    35. connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    36.  
    37. qDebug()<<"New connection started..run." ;
    38. //! [1] //! [2]
    39.  
    40.  
    41.  
    42.  
    43. }
    44. void WebProxyThread::manageQuery() {
    45. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender());
    46. QTcpSocket *socket = proxyServer->nextPendingConnection();
    47. connect(socket, SIGNAL(readyRead()), this, SLOT(processQuery()));
    48. connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    49. qDebug()<<"New connection started..."<<socket->peerAddress();
    50. }
    51. QUrl WebProxyThread::getUrl(QList<QByteArray > &entries)
    52. {
    53.  
    54. QByteArray method = entries.value(0);
    55. QByteArray address = entries.value(1);
    56. QByteArray version = entries.value(2);
    57.  
    58. qDebug()<<method;
    59. qDebug()<<address;
    60. qDebug()<<version;
    61. QUrl url = QUrl::fromEncoded(address);
    62. if (!url.isValid()) {
    63.  
    64. qWarning() << "Invalid URL:" << url;
    65.  
    66. return QString();
    67. }
    68.  
    69.  
    70. return url;
    71. }
    72.  
    73. void WebProxyThread::processQuery() {
    74.  
    75.  
    76. QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
    77. QByteArray requestData = socket->readAll();
    78. int pos = requestData.indexOf("\r\n");
    79. QByteArray requestLine = requestData.left(pos);
    80. requestData.remove(0, pos + 2);
    81. QList<QByteArray> entries = requestLine.split(' ');
    82. QByteArray method = entries.value(0);
    83. QByteArray address = entries.value(1);
    84. QByteArray version = entries.value(2);
    85.  
    86. QUrl url = QUrl::fromEncoded(address);
    87. if (!url.isValid()) {
    88. qWarning() << "Invalid URL:" << url;
    89. socket->disconnectFromHost();
    90. return;
    91. }
    92.  
    93. QString host = url.host();
    94.  
    95. int port = (url.port() <= 0) ? 80 : url.port();
    96. QByteArray req = url.encodedPath();
    97. if (url.hasQuery())
    98. req.append('?').append(url.encodedQuery());
    99.  
    100. requestLine = method + " " + req + " " + version + "\r\n";
    101. requestData.prepend(requestLine);
    102. QString key = host + ':' + QString::number(port);
    103. QTcpSocket *proxySocket = socket->findChild<QTcpSocket*>(key);
    104. if (proxySocket) {
    105. proxySocket->setObjectName(key);
    106. proxySocket->setProperty("url", url);
    107. proxySocket->setProperty("requestData", requestData);
    108. proxySocket->write(requestData);
    109. } else {
    110. proxySocket = new QTcpSocket(socket);
    111. proxySocket->setObjectName(key);
    112. proxySocket->setProperty("url", url);
    113. proxySocket->setProperty("requestData", requestData);
    114. connect(proxySocket, SIGNAL(connected()), this, SLOT(sendRequest()));
    115. connect(proxySocket, SIGNAL(readyRead()), this, SLOT(transferData()));
    116. connect(proxySocket, SIGNAL(disconnected()), this, SLOT(closeConnection()));
    117. connect(proxySocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(closeConnection()));
    118. proxySocket->connectToHost(host, port);
    119. }
    120. }
    121.  
    122. void WebProxyThread::sendRequest() {
    123. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    124. QByteArray requestData = proxySocket->property("requestData").toByteArray();
    125. proxySocket->write(requestData);
    126. }
    127.  
    128. void WebProxyThread::transferData() {
    129. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    130. QByteArray data = proxySocket->readAll();
    131. QString host = proxySocket->peerAddress().toString();
    132. QByteArray filtered(data);
    133. if (hashDvr.value(host) == 1)
    134. {
    135.  
    136. QString name = hashUFormat.value(host);
    137. QString pass = hashPFormat.value(host);
    138. QString repU = "name=" + name + " value=" + hashUsername.value(host);
    139. QString repP = "name="+ pass + " value=" + hashPassword.value(host);
    140. QString submit = hashSubmit.value(host);
    141. QString search = hashSearch.value(host);
    142. filtered.replace("name=" + name,repU.toLocal8Bit());
    143. filtered.replace("name=" + pass,repP.toLocal8Bit());
    144. filtered.replace(search.toLocal8Bit(),submit.toLocal8Bit());
    145. }
    146. QTcpSocket *socket = qobject_cast<QTcpSocket*>(proxySocket->parent());
    147. socket->write(filtered);
    148. }
    149.  
    150. void WebProxyThread::closeConnection() {
    151. QTcpSocket *proxySocket = qobject_cast<QTcpSocket*>(sender());
    152. if (proxySocket) {
    153. QTcpSocket *socket = qobject_cast<QTcpSocket*>(proxySocket->parent());
    154. if (socket)
    155. socket->disconnectFromHost();
    156. if (proxySocket->error() != QTcpSocket::RemoteHostClosedError)
    157. qWarning() << "Error for:" << proxySocket->property("url").toUrl()
    158. << proxySocket->errorString();
    159. proxySocket->deleteLater();;
    160. }
    161. }
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: A Web Proxy multithread

    That's completely incorrect. There are lots of errors.

    One thing I'm pretty sure off is that the proxyServer pointer points to nothing or nothing usable.

    What does the following code do?
    Qt Code:
    1. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender());
    To copy to clipboard, switch view to plain text mode 
    Can you explain this?

  5. #5
    Join Date
    May 2008
    Posts
    276
    Thanks
    13
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: A Web Proxy multithread

    It should triy to guess who is the sender of the signal....
    G

  6. #6
    Join Date
    Jul 2011
    Location
    Brasil
    Posts
    39
    Thanks
    1
    Thanked 7 Times in 7 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: A Web Proxy multithread

    tbscope is right...

    When you connect proxyServer::newConnection and WebProxy::go(), they are on the same thread, so it is a direct connection. When this happens, Qt doesn't fill up the sender() value... so, when you do it in your wpt->start(), which calls run(), you are using a null value.
    As a try, you can replace
    Qt Code:
    1. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender());
    To copy to clipboard, switch view to plain text mode 
    by
    Qt Code:
    1. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(parent());
    To copy to clipboard, switch view to plain text mode 

    BTW, I think you will need at least one mutex to protect the following
    Qt Code:
    1. QTcpServer *proxyServer = qobject_cast<QTcpServer*>(sender()); //this you should review
    2. QTcpSocket *socket = proxyServer->nextPendingConnection();
    To copy to clipboard, switch view to plain text mode 
    to avoid lost connections.
    Try making this a piece of WebProxy implementation, instead of doing this in the thread start...

    Or better: catch the nextPendigConnection, and pass it to constructor of the thread object (using socket descriptor, not sure if you can use a QTcpSocket across different threads)... and then use the QAbstractSocket::setSocketDescriptor at thread startup...

    hth.

Similar Threads

  1. Multithread in multicore CPU
    By ^NyAw^ in forum General Discussion
    Replies: 12
    Last Post: 26th December 2017, 14:19
  2. I don't quite understand this multithread example
    By HelloDan in forum Qt Programming
    Replies: 2
    Last Post: 9th April 2009, 08:58
  3. Problem with MultiThread..
    By blm in forum Qt Programming
    Replies: 6
    Last Post: 15th September 2008, 10:48
  4. about multithread
    By Pang in forum Qt Programming
    Replies: 2
    Last Post: 22nd June 2007, 18:06
  5. Help me about multithread!
    By vql in forum Newbie
    Replies: 19
    Last Post: 8th February 2007, 15:01

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.