* PIThread::~PIThread() now unregister itself from introspection, if terminates than show warning * PISystemMonitor now correctly stops * PIPeer now can correctly stopAndWait * PIPeer::destroy(), protected method for close all eths and threads * new PIINTROSPECTION_STOP macro * Introspection now can be correctly stopped by macro, more safety ClientServer: * ClientBase::close() stop and disconnect channel * Server clients clean-up now event-based * No warnings on client destructor
138 lines
3.3 KiB
C++
138 lines
3.3 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
Ivan Pelipenko peri4ko@yandex.ru
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "piclientserver_server.h"
|
|
|
|
#include "piclientserver_client.h"
|
|
#include "piethernet.h"
|
|
#include "piliterals_time.h"
|
|
|
|
|
|
PIClientServer::Server::Server() {
|
|
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
|
|
clean_thread = new PIThread();
|
|
client_factory = [] { return new ServerClient(); };
|
|
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
|
|
PIMutexLocker guard(clients_mutex);
|
|
if (clients.size_s() >= max_clients) {
|
|
piCout << "Server::newConnection overflow clients count";
|
|
delete c;
|
|
return;
|
|
}
|
|
auto sc = client_factory();
|
|
if (!sc) {
|
|
piCout << "ClientFactory returns nullptr!";
|
|
return;
|
|
}
|
|
sc->createForServer(this, c);
|
|
newClient(sc);
|
|
});
|
|
|
|
clean_thread->start([this]() {
|
|
clean_notifier.wait();
|
|
PIVector<ServerClient *> to_delete;
|
|
clients_mutex.lock();
|
|
for (auto c: clients) {
|
|
const PIEthernet * eth = c->getTCP();
|
|
if (!eth) continue;
|
|
if (eth->isConnected()) continue;
|
|
c->can_write = false;
|
|
to_delete << c;
|
|
}
|
|
for (auto c: to_delete)
|
|
clients.removeOne(c);
|
|
clients_mutex.unlock();
|
|
for (auto c: to_delete) {
|
|
c->aboutDelete();
|
|
c->destroy();
|
|
delete c;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
PIClientServer::Server::~Server() {
|
|
clean_thread->stop();
|
|
clean_notifier.notify();
|
|
clean_thread->waitForFinish();
|
|
piDeleteSafety(clean_thread);
|
|
stopServer();
|
|
for (auto c: clients) {
|
|
c->aboutDelete();
|
|
c->destroy();
|
|
delete c;
|
|
}
|
|
piDeleteSafety(tcp_server);
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::listen(PINetworkAddress addr) {
|
|
if (!tcp_server) return;
|
|
stopServer();
|
|
is_closing = false;
|
|
tcp_server->listen(addr, true);
|
|
// piCout << "Listen on" << addr.toString();
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::setMaxClients(int new_max_clients) {
|
|
max_clients = new_max_clients;
|
|
}
|
|
|
|
|
|
int PIClientServer::Server::clientsCount() const {
|
|
PIMutexLocker guard(clients_mutex);
|
|
return clients.size_s();
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
|
|
PIMutexLocker guard(clients_mutex);
|
|
for (auto * c: clients) {
|
|
func(c);
|
|
if (is_closing) break;
|
|
}
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::enableSymmetricEncryption(const PIByteArray & key) {
|
|
crypt_key = key;
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::stopServer() {
|
|
if (!tcp_server) return;
|
|
is_closing = true;
|
|
tcp_server->stopThreadedListen();
|
|
tcp_server->stopAndWait();
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::newClient(ServerClient * c) {
|
|
clients << c;
|
|
c->enableSymmetricEncryption(crypt_key);
|
|
c->tcp->startThreadedRead();
|
|
c->connected();
|
|
piCout << "New client";
|
|
}
|
|
|
|
|
|
void PIClientServer::Server::clientDisconnected(ServerClient * c) {
|
|
clean_notifier.notify();
|
|
}
|