Heart/ClientProtocol/abstractnode.cpp

354 lines
9.0 KiB
C++
Raw Normal View History

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
}
}