From 48bef601de79df7a3d215f07c24e16eba79b9640 Mon Sep 17 00:00:00 2001 From: adityapk00 Date: Thu, 18 Apr 2019 21:02:07 -0700 Subject: [PATCH] Fix access violation --- src/websockets.cpp | 34 +++++++++++++++++++++++----------- src/websockets.h | 27 ++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/websockets.cpp b/src/websockets.cpp index ccfd42c..f5c6bde 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -5,6 +5,19 @@ #include "ui_mobileappconnector.h" #include "version.h" +// Weap the sendTextMessage to check if the connection is valid and that the parent WebServer didn't close this connection +// for some reason. +void ClientWebSocket::sendTextMessage(QString m) { + if (client) { + if (server && !server->isValidConnection(client)) { + return; + } + + if (client->isValid()) + client->sendTextMessage(m); + } +} + WSServer::WSServer(quint16 port, bool debug, QObject *parent) : QObject(parent), m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Direct Connection Server"), @@ -46,7 +59,8 @@ void WSServer::processTextMessage(QString message) qDebug() << "Message received:" << message; if (pClient) { - AppDataServer::getInstance()->processMessage(message, m_mainWindow, pClient, AppConnectionType::DIRECT); + std::shared_ptr client = std::make_shared(pClient, this); + AppDataServer::getInstance()->processMessage(message, m_mainWindow, client, AppConnectionType::DIRECT); } } @@ -153,7 +167,7 @@ void WormholeClient::onConnected() void WormholeClient::onTextMessageReceived(QString message) { - AppDataServer::getInstance()->processMessage(message, parent, m_webSocket, AppConnectionType::INTERNET); + AppDataServer::getInstance()->processMessage(message, parent, std::make_shared(m_webSocket), AppConnectionType::INTERNET); } @@ -508,7 +522,7 @@ QString AppDataServer::decryptMessage(QJsonDocument msg, QString secretHex, QStr } // Process an incoming text message. The message has to be encrypted with the secret key (or the temporary secret key) -void AppDataServer::processMessage(QString message, MainWindow* mainWindow, QWebSocket* pClient, AppConnectionType connType) { +void AppDataServer::processMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient, AppConnectionType connType) { auto replyWithError = [=]() { auto r = QJsonDocument(QJsonObject{ {"error", "Encryption error"}, @@ -591,7 +605,7 @@ void AppDataServer::processMessage(QString message, MainWindow* mainWindow, QWeb } // Decrypted method will be executed here. -void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWindow, QWebSocket* pClient) { +void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient) { // First, extract the command from the message auto msg = QJsonDocument::fromJson(message.toUtf8()); @@ -623,7 +637,7 @@ void AppDataServer::processDecryptedMessage(QString message, MainWindow* mainWin } // "sendTx" command. This method will actually send money, so be careful with everything -void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QWebSocket* pClient) { +void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr pClient) { auto error = [=](QString reason) { auto r = QJsonDocument(QJsonObject{ {"errorCode", -1}, @@ -693,8 +707,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QW {"command", "sendTxSubmitted"}, {"txid", txid} }).toJson(); - if (pClient->isValid()) - pClient->sendTextMessage(encryptOutgoing(r)); + pClient->sendTextMessage(encryptOutgoing(r)); }, // Errored while submitting Tx [=] (QString, QString errStr) { @@ -703,8 +716,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QW {"command", "sendTxFailed"}, {"err", errStr} }).toJson(); - if (pClient->isValid()) - pClient->sendTextMessage(encryptOutgoing(r)); + pClient->sendTextMessage(encryptOutgoing(r)); } ); @@ -717,7 +729,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QW } // "getInfo" command -void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, QWebSocket* pClient) { +void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr pClient) { auto connectedName = jobj["name"].toString(); if (mainWindow == nullptr || mainWindow->getRPC() == nullptr || @@ -758,7 +770,7 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, QWe pClient->sendTextMessage(encryptOutgoing(r)); } -void AppDataServer::processGetTransactions(MainWindow* mainWindow, QWebSocket* pClient) { +void AppDataServer::processGetTransactions(MainWindow* mainWindow, std::shared_ptr pClient) { QJsonArray txns; auto model = mainWindow->getRPC()->getTransactionsModel(); diff --git a/src/websockets.h b/src/websockets.h index c5b7d56..4758f1c 100644 --- a/src/websockets.h +++ b/src/websockets.h @@ -10,11 +10,28 @@ QT_FORWARD_DECLARE_CLASS(QWebSocketServer) QT_FORWARD_DECLARE_CLASS(QWebSocket) +class WSServer; + +// We're going to wrap the websocket in this class, because the underlying QWebSocket might get closed +// or deleted while a callback is waiting to get the data back. Therefore, we write a custom "sendTextMessage" +// class that checks all this before sending. +class ClientWebSocket { +public: + ClientWebSocket(QWebSocket* c, WSServer* s = nullptr) { client = c; server = s; } + + void sendTextMessage(QString m); + void close(QWebSocketProtocol::CloseCode code, const QString& msg) { client->close(code, msg); } +private: + QWebSocket* client; + WSServer* server; +}; + class WSServer : public QObject { Q_OBJECT public: explicit WSServer(quint16 port, bool debug = false, QObject *parent = nullptr); + bool isValidConnection(QWebSocket* c) { return m_clients.contains(c); } ~WSServer(); Q_SIGNALS: @@ -82,11 +99,11 @@ public: void updateConnectedUI(); void updateUIWithNewQRCode(MainWindow* mainwindow); - void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, QWebSocket* pClient); - void processMessage(QString message, MainWindow* mainWindow, QWebSocket* pClient, AppConnectionType connType); - void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, QWebSocket* pClient); - void processDecryptedMessage(QString message, MainWindow* mainWindow, QWebSocket* pClient); - void processGetTransactions(MainWindow* mainWindow, QWebSocket* pClient); + void processSendTx(QJsonObject sendTx, MainWindow* mainwindow, std::shared_ptr pClient); + void processMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient, AppConnectionType connType); + void processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std::shared_ptr pClient); + void processDecryptedMessage(QString message, MainWindow* mainWindow, std::shared_ptr pClient); + void processGetTransactions(MainWindow* mainWindow, std::shared_ptr pClient); QString decryptMessage(QJsonDocument msg, QString secretHex, QString lastRemoteNonceHex); QString encryptOutgoing(QString msg);