2019-10-10 17:56:57 +03:00
|
|
|
#include "abstractdata.h"
|
2019-10-09 17:58:58 +03:00
|
|
|
#include "abstractnode.h"
|
2019-10-11 18:30:09 +03:00
|
|
|
#include <QSslSocket>
|
2019-10-10 17:56:57 +03:00
|
|
|
#include <quasarapp.h>
|
|
|
|
|
2019-10-09 17:58:58 +03:00
|
|
|
namespace ClientProtocol {
|
|
|
|
|
2019-10-10 17:56:57 +03:00
|
|
|
AbstractNode::AbstractNode(bool ssl, QObject *ptr):
|
|
|
|
QTcpServer(ptr) {
|
|
|
|
useSSL = ssl;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::run(const QString &addres, unsigned short port) {
|
|
|
|
if (!listen(QHostAddress(addres), port)) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("Run fail " + this->errorString(),
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractNode::stop() {
|
|
|
|
close();
|
|
|
|
|
|
|
|
for (auto &&i : _connections) {
|
|
|
|
i.info.disconnect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AbstractNodeInfo *AbstractNode::getInfoPtr(quint32 id) {
|
|
|
|
if (!_connections.contains(id)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &_connections[id].info;
|
|
|
|
}
|
|
|
|
|
|
|
|
AbstractNodeInfo AbstractNode::getInfo(quint32 id) const{
|
|
|
|
return _connections.value(id).info;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
AbstractNodeInfo *AbstractNode::getInfoPtr(const QHostAddress &id) {
|
|
|
|
return getInfoPtr(qHash(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
AbstractNodeInfo AbstractNode::getInfo(const QHostAddress &id) const {
|
|
|
|
return getInfo(qHash(id));
|
|
|
|
}
|
|
|
|
|
2019-10-10 17:56:57 +03:00
|
|
|
void AbstractNode::ban(quint32 target) {
|
|
|
|
|
|
|
|
auto info = getInfoPtr(target);
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
_connections[target] = NodeInfoData{};
|
|
|
|
|
|
|
|
_connections[target].info.ban();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractNode::unBan(quint32 target) {
|
|
|
|
if (!_connections.contains(target)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_connections[target].info.unBan();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short AbstractNode::port() const {
|
|
|
|
return serverPort();
|
|
|
|
}
|
|
|
|
|
|
|
|
QHostAddress AbstractNode::address() const {
|
|
|
|
return serverAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
AbstractNode::~AbstractNode() {
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::registerSocket(QAbstractSocket *socket) {
|
|
|
|
|
|
|
|
auto info = AbstractNodeInfo(socket);
|
|
|
|
_connections[info.id()] = {info, {}};
|
|
|
|
|
|
|
|
connect(socket, &QAbstractSocket::readyRead, this, &AbstractNode::avelableBytes);
|
|
|
|
connect(socket, &QAbstractSocket::disconnected, this, &AbstractNode::handleDisconnected);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
bool AbstractNode::parsePackage(const BasePackage &pkg, AbstractNodeInfo *sender) {
|
2019-10-10 17:56:57 +03:00
|
|
|
|
|
|
|
if (!pkg.isValid()) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("incomming package is not valid!",
|
|
|
|
QuasarAppUtils::Error);
|
2019-10-11 18:30:09 +03:00
|
|
|
changeTrust(sender->id(), CRITICAL_ERROOR);
|
2019-10-10 17:56:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sender->isValid()) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("sender socket is not valid!",
|
|
|
|
QuasarAppUtils::Error);
|
2019-10-11 18:30:09 +03:00
|
|
|
changeTrust(sender->id(), LOGICK_ERROOR);
|
2019-10-10 17:56:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
emit incomingReques(pkg, sender->id());
|
2019-10-10 17:56:57 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::sendPackage(const BasePackage &pkg, QAbstractSocket *target) {
|
|
|
|
if (!pkg.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!target || !target->isValid()) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("destination server not valid!",
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!target->waitForConnected()) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("no connected to server! " + target->errorString(),
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto bytes = pkg.toBytes();
|
|
|
|
bool sendet = bytes.size() == target->write(bytes);
|
|
|
|
|
|
|
|
return sendet;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::sendResponse(const AbstractData &resp, quint32 id, const BaseHeader *req) {
|
|
|
|
auto client = getInfoPtr(id);
|
|
|
|
|
|
|
|
if (!client) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("Response not sent because client == null",
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BasePackage pkg;
|
|
|
|
if (!resp.toPackage(pkg, req->command)) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("Response not sent because dont create package from object",
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sendPackage(pkg, client->sct())) {
|
|
|
|
QuasarAppUtils::Params::verboseLog("Response not sent!",
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TO DO hasPendingConnections is no implementing
|
|
|
|
QString AbstractNode::getWorkState() const {
|
|
|
|
if (isListening()) {
|
|
|
|
if (hasPendingConnections())
|
|
|
|
return "overload";
|
|
|
|
else {
|
|
|
|
return "Work";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Not running";
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AbstractNode::connectionState() const {
|
|
|
|
return QString("%0 / %1").arg(connectionsCount()).arg(maxPendingConnections());
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AbstractNode::baned() const {
|
|
|
|
QStringList list = {};
|
|
|
|
for (auto i = _connections.begin(); i != _connections.end(); ++i) {
|
2019-10-11 18:30:09 +03:00
|
|
|
if (i.value().info.isBaned()) {
|
2019-10-10 17:56:57 +03:00
|
|
|
list.push_back(QHostAddress(i.key()).toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AbstractNode::connectionsCount() const {
|
|
|
|
int count = 0;
|
|
|
|
for (auto i : _connections) {
|
2019-10-11 18:30:09 +03:00
|
|
|
if (i.info.sct()) {
|
|
|
|
if (!i.info.sct()->isValid()) {
|
2019-10-10 17:56:57 +03:00
|
|
|
QuasarAppUtils::Params::verboseLog("connection count, findet not valid socket",
|
|
|
|
QuasarAppUtils::Warning);
|
|
|
|
}
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::isBaned(QAbstractSocket *socket) const {
|
2019-10-11 18:30:09 +03:00
|
|
|
auto info = getInfo(socket->peerAddress());
|
2019-10-10 17:56:57 +03:00
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
if (!info.isValid()) {
|
2019-10-10 17:56:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
return info.isBaned();
|
2019-10-10 17:56:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractNode::incomingConnection(qintptr handle) {
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
if (useSSL) {
|
|
|
|
incomingSsl(handle);
|
|
|
|
} else {
|
|
|
|
incomingTcp(handle);
|
|
|
|
}
|
2019-10-10 17:56:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AbstractNode::changeTrust(quint32 id, int diff) {
|
|
|
|
auto ptr = getInfoPtr(id);
|
|
|
|
if (!ptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto objTrust = ptr->trust();
|
|
|
|
|
|
|
|
if (objTrust >= static_cast<int>(TrustNode::Undefined)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (objTrust <= static_cast<int>(TrustNode::Baned)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr->setTrust(objTrust + diff);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
void AbstractNode::incomingSsl(qintptr socketDescriptor) {
|
|
|
|
QSslSocket *serverSocket = new QSslSocket;
|
|
|
|
|
|
|
|
serverSocket->setProtocol(QSsl::TlsV1_3);
|
|
|
|
serverSocket->setLocalCertificate(QSslCertificate());
|
|
|
|
|
|
|
|
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
|
|
|
connect(serverSocket, &QSslSocket::encrypted, [this, serverSocket](){
|
|
|
|
registerSocket(serverSocket);
|
|
|
|
});
|
|
|
|
|
|
|
|
connect(serverSocket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
|
|
|
|
[serverSocket](const QList<QSslError> &errors){
|
|
|
|
|
|
|
|
for (auto &error : errors) {
|
|
|
|
QuasarAppUtils::Params::verboseLog(error.errorString(), QuasarAppUtils::Error);
|
|
|
|
}
|
|
|
|
|
|
|
|
serverSocket->deleteLater();
|
|
|
|
});
|
|
|
|
|
|
|
|
serverSocket->startServerEncryption();
|
|
|
|
} else {
|
|
|
|
delete serverSocket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractNode::incomingTcp(qintptr socketDescriptor) {
|
|
|
|
QTcpSocket *serverSocket = new QTcpSocket;
|
|
|
|
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
|
|
|
connect(serverSocket, &QSslSocket::encrypted, [this, serverSocket](){
|
|
|
|
registerSocket(serverSocket);
|
|
|
|
});
|
|
|
|
|
|
|
|
connect(serverSocket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
|
|
|
|
[serverSocket](const QList<QSslError> &errors){
|
|
|
|
|
|
|
|
for (auto &error : errors) {
|
|
|
|
QuasarAppUtils::Params::verboseLog(error.errorString(), QuasarAppUtils::Error);
|
|
|
|
}
|
|
|
|
|
|
|
|
serverSocket->deleteLater();
|
|
|
|
});
|
|
|
|
|
|
|
|
serverSocket->startServerEncryption();
|
|
|
|
} else {
|
|
|
|
delete serverSocket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 17:56:57 +03:00
|
|
|
|
|
|
|
void AbstractNode::avelableBytes() {
|
2019-10-11 18:30:09 +03:00
|
|
|
|
|
|
|
auto client = dynamic_cast<QAbstractSocket*>(sender());
|
2019-10-10 17:56:57 +03:00
|
|
|
|
|
|
|
if (!client) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
auto id = qHash(client->peerAddress());
|
|
|
|
|
|
|
|
if (!_connections.contains(id)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-10-10 17:56:57 +03:00
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
auto &val = _connections[id];
|
|
|
|
|
|
|
|
auto array = client->readAll();
|
|
|
|
if (val.pkg.hdr.isValid()) {
|
|
|
|
val.pkg.data.append(array);
|
2019-10-10 17:56:57 +03:00
|
|
|
|
|
|
|
} else {
|
2019-10-11 18:30:09 +03:00
|
|
|
val.pkg.reset();
|
2019-10-10 17:56:57 +03:00
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
memcpy(&val.pkg.hdr,
|
2019-10-10 17:56:57 +03:00
|
|
|
array.data(), sizeof(BaseHeader));
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
val.pkg.data.append(array.mid(sizeof(BaseHeader)));
|
2019-10-10 17:56:57 +03:00
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
if (val.pkg.isValid()) {
|
|
|
|
parsePackage(val.pkg, &val.info);
|
2019-10-10 17:56:57 +03:00
|
|
|
}
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
if (val.pkg.data.size() >= val.pkg.hdr.size) {
|
|
|
|
val.pkg.reset();
|
2019-10-10 17:56:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractNode::handleDisconnected() {
|
|
|
|
auto _sender = dynamic_cast<QTcpSocket*>(sender());
|
|
|
|
|
|
|
|
if (_sender) {
|
|
|
|
// log error
|
|
|
|
|
2019-10-11 18:30:09 +03:00
|
|
|
auto ptr = getInfoPtr(_sender->peerAddress());
|
2019-10-10 17:56:57 +03:00
|
|
|
if (ptr) {
|
|
|
|
ptr->disconnect();
|
|
|
|
} else {
|
|
|
|
QuasarAppUtils::Params::verboseLog("system error in void Server::handleDisconected()"
|
|
|
|
" address not valid",
|
|
|
|
QuasarAppUtils::Error);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2019-10-09 17:58:58 +03:00
|
|
|
|
2019-10-10 17:56:57 +03:00
|
|
|
QuasarAppUtils::Params::verboseLog("system error in void Server::handleDisconected()"
|
|
|
|
"dynamic_cast fail!",
|
|
|
|
QuasarAppUtils::Error);
|
2019-10-09 17:58:58 +03:00
|
|
|
}
|
|
|
|
}
|