Client Websockets (#3545)

* Websockets

* Add setting to get websocket IP from header

* Add QT version guard

* Minor cleanup

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* - Make QWebSocket required
- Remove QWEBSOCEKT_LIB guards
- Only TCP on port 4747
- Fix peerName lookup

* fix check

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* Update CMakeLists.txt

* Update CMakeLists.txt
This commit is contained in:
Rob Blanckaert 2019-02-03 02:43:22 -08:00 committed by ctrlaltca
parent 5e38214675
commit 9a8c81cf5e
8 changed files with 130 additions and 77 deletions

View file

@ -18,12 +18,13 @@
#include <QList>
#include <QThread>
#include <QTimer>
#include <QWebSocket>
static const unsigned int protocolVersion = 14;
RemoteClient::RemoteClient(QObject *parent)
: AbstractClient(parent), timeRunning(0), lastDataReceived(0), messageInProgress(false), handshakeStarted(false),
messageLength(0)
usingWebSocket(false), messageLength(0)
{
clearNewClientFeatures();
@ -38,6 +39,13 @@ RemoteClient::RemoteClient(QObject *parent)
connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(slotSocketError(QAbstractSocket::SocketError)));
websocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
connect(websocket, &QWebSocket::binaryMessageReceived, this, &RemoteClient::websocketMessageReceived);
connect(websocket, &QWebSocket::connected, this, &RemoteClient::slotConnected);
connect(websocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(slotWebSocketError(QAbstractSocket::SocketError)));
connect(this, SIGNAL(serverIdentificationEventReceived(const Event_ServerIdentification &)), this,
SLOT(processServerIdentificationEvent(const Event_ServerIdentification &)));
connect(this, SIGNAL(connectionClosedEventReceived(Event_ConnectionClosed)), this,
@ -69,15 +77,25 @@ void RemoteClient::slotSocketError(QAbstractSocket::SocketError /*error*/)
emit socketError(errorString);
}
void RemoteClient::slotWebSocketError(QAbstractSocket::SocketError /*error*/)
{
QString errorString = websocket->errorString();
doDisconnectFromServer();
emit socketError(errorString);
}
void RemoteClient::slotConnected()
{
timeRunning = lastDataReceived = 0;
timer->start();
// dirty hack to be compatible with v14 server
sendCommandContainer(CommandContainer());
getNewCmdId();
// end of hack
if (!usingWebSocket) {
// dirty hack to be compatible with v14 server
sendCommandContainer(CommandContainer());
getNewCmdId();
// end of hack
}
}
void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentification &event)
@ -217,7 +235,7 @@ void RemoteClient::loginResponse(const Response &response)
missingFeatures << QString::fromStdString(resp.missing_features(i));
}
emit loginError(response.response_code(), QString::fromStdString(resp.denied_reason_str()),
resp.denied_end_time(), missingFeatures);
static_cast<quint32>(resp.denied_end_time()), missingFeatures);
setStatus(StatusDisconnecting);
}
}
@ -236,7 +254,7 @@ void RemoteClient::registerResponse(const Response &response)
break;
default:
emit registerError(response.response_code(), QString::fromStdString(resp.denied_reason_str()),
resp.denied_end_time());
static_cast<quint32>(resp.denied_end_time()));
setStatus(StatusDisconnecting);
doDisconnectFromServer();
break;
@ -301,21 +319,51 @@ void RemoteClient::readData()
} while (!inputBuffer.isEmpty());
}
void RemoteClient::websocketMessageReceived(const QByteArray &message)
{
lastDataReceived = timeRunning;
ServerMessage newServerMessage;
newServerMessage.ParseFromArray(message.data(), message.length());
#ifdef QT_DEBUG
qDebug() << "IN" << messageLength << QString::fromStdString(newServerMessage.ShortDebugString());
#endif
processProtocolItem(newServerMessage);
}
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
{
QByteArray buf;
unsigned int size = cont.ByteSize();
auto size = static_cast<unsigned int>(cont.ByteSize());
#ifdef QT_DEBUG
qDebug() << "OUT" << size << QString::fromStdString(cont.ShortDebugString());
#endif
buf.resize(size + 4);
cont.SerializeToArray(buf.data() + 4, size);
buf.data()[3] = (unsigned char)size;
buf.data()[2] = (unsigned char)(size >> 8);
buf.data()[1] = (unsigned char)(size >> 16);
buf.data()[0] = (unsigned char)(size >> 24);
socket->write(buf);
QByteArray buf;
if (usingWebSocket) {
buf.resize(size);
cont.SerializeToArray(buf.data(), size);
websocket->sendBinaryMessage(buf);
} else {
buf.resize(size + 4);
cont.SerializeToArray(buf.data() + 4, size);
buf.data()[3] = (unsigned char)size;
buf.data()[2] = (unsigned char)(size >> 8);
buf.data()[1] = (unsigned char)(size >> 16);
buf.data()[0] = (unsigned char)(size >> 24);
socket->write(buf);
}
}
void RemoteClient::connectToHost(const QString &hostname, unsigned int port)
{
usingWebSocket = port == 443 || port == 80 || port == 4748 || port == 8080;
if (usingWebSocket) {
QUrl url(QString("%1://%2:%3").arg(port == 443 ? "wss" : "ws").arg(hostname).arg(port));
websocket->open(url);
} else {
socket->connectToHost(hostname, static_cast<quint16>(port));
}
}
void RemoteClient::doConnectToServer(const QString &hostname,
@ -330,7 +378,7 @@ void RemoteClient::doConnectToServer(const QString &hostname,
lastHostname = hostname;
lastPort = port;
socket->connectToHost(hostname, port);
connectToHost(hostname, port);
setStatus(StatusConnecting);
}
@ -354,7 +402,7 @@ void RemoteClient::doRegisterToServer(const QString &hostname,
lastHostname = hostname;
lastPort = port;
socket->connectToHost(hostname, port);
connectToHost(hostname, port);
setStatus(StatusRegistering);
}
@ -364,7 +412,7 @@ void RemoteClient::doActivateToServer(const QString &_token)
token = _token;
socket->connectToHost(lastHostname, lastPort);
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
setStatus(StatusActivating);
}
@ -377,17 +425,19 @@ void RemoteClient::doDisconnectFromServer()
messageLength = 0;
QList<PendingCommand *> pc = pendingCommands.values();
for (int i = 0; i < pc.size(); i++) {
for (const auto &i : pc) {
Response response;
response.set_response_code(Response::RespNotConnected);
response.set_cmd_id(pc[i]->getCommandContainer().cmd_id());
pc[i]->processResponse(response);
response.set_cmd_id(i->getCommandContainer().cmd_id());
i->processResponse(response);
delete pc[i];
delete i;
}
pendingCommands.clear();
setStatus(StatusDisconnected);
if (websocket->isValid())
websocket->close();
socket->close();
}
@ -508,7 +558,7 @@ void RemoteClient::doRequestForgotPasswordToServer(const QString &hostname, unsi
lastHostname = hostname;
lastPort = port;
socket->connectToHost(lastHostname, lastPort);
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
setStatus(StatusRequestingForgotPassword);
}
@ -540,7 +590,7 @@ void RemoteClient::doSubmitForgotPasswordResetToServer(const QString &hostname,
token = _token;
password = _newpassword;
socket->connectToHost(lastHostname, lastPort);
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
setStatus(StatusSubmitForgotPasswordReset);
}
@ -574,7 +624,7 @@ void RemoteClient::doSubmitForgotPasswordChallengeToServer(const QString &hostna
lastPort = port;
email = _email;
socket->connectToHost(lastHostname, lastPort);
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
setStatus(StatusSubmitForgotPasswordChallenge);
}

View file

@ -3,6 +3,7 @@
#include "abstractclient.h"
#include <QTcpSocket>
#include <QWebSocket>
class QTimer;
@ -17,7 +18,6 @@ signals:
void activateError();
void socketError(const QString &errorString);
void protocolVersionMismatch(int clientVersion, int serverVersion);
void protocolError();
void
sigConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password);
void sigRegisterToServer(const QString &hostname,
@ -25,7 +25,7 @@ signals:
const QString &_userName,
const QString &_password,
const QString &_email,
const int _gender,
int _gender,
const QString &_country,
const QString &_realname);
void sigActivateToServer(const QString &_token);
@ -48,7 +48,9 @@ signals:
private slots:
void slotConnected();
void readData();
void websocketMessageReceived(const QByteArray &message);
void slotSocketError(QAbstractSocket::SocketError error);
void slotWebSocketError(QAbstractSocket::SocketError error);
void ping();
void processServerIdentificationEvent(const Event_ServerIdentification &event);
void processConnectionClosedEvent(const Event_ConnectionClosed &event);
@ -62,7 +64,7 @@ private slots:
const QString &_userName,
const QString &_password,
const QString &_email,
const int _gender,
int _gender,
const QString &_country,
const QString &_realname);
void doLogin();
@ -85,28 +87,35 @@ private slots:
private:
static const int maxTimeout = 10;
int timeRunning, lastDataReceived;
QByteArray inputBuffer;
bool messageInProgress;
bool handshakeStarted;
bool newMissingFeatureFound(QString _serversMissingFeatures);
void clearNewClientFeatures();
bool usingWebSocket;
int messageLength;
QTimer *timer;
QTcpSocket *socket;
QWebSocket *websocket;
QString lastHostname;
int lastPort;
QString getSrvClientID(const QString _hostname);
QString getSrvClientID(QString _hostname);
bool newMissingFeatureFound(QString _serversMissingFeatures);
void clearNewClientFeatures();
void connectToHost(const QString &hostname, unsigned int port);
protected slots:
void sendCommandContainer(const CommandContainer &cont);
void sendCommandContainer(const CommandContainer &cont) override;
public:
RemoteClient(QObject *parent = 0);
~RemoteClient();
explicit RemoteClient(QObject *parent = nullptr);
~RemoteClient() override;
QString peerName() const
{
return socket->peerName();
if (usingWebSocket) {
return websocket->peerName();
} else {
return socket->peerName();
}
}
void
connectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password);
@ -115,7 +124,7 @@ public:
const QString &_userName,
const QString &_password,
const QString &_email,
const int _gender,
int _gender,
const QString &_country,
const QString &_realname);
void activateToServer(const QString &_token);