/* 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 . */ #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 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 func) { PIMutexLocker guard(clients_mutex); for (auto * c: clients) { func(c); if (is_closing) break; } } 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; config.apply(c); c->tcp->startThreadedRead(); c->connected(); piCout << "New client"; } void PIClientServer::Server::clientDisconnected(ServerClient * c) { clean_notifier.notify(); }