diff --git a/src/core/server.cpp b/src/core/server.cpp index 49fea4a..c8ed18c 100755 --- a/src/core/server.cpp +++ b/src/core/server.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include namespace Yc { namespace Lib { @@ -63,13 +65,33 @@ namespace Yc { } } + Server::~Server() { + stop(); + if (_socket >= 0) { + close(_socket); + _socket = -1; + } + } + + void Server::stop() { + std::cout << "[YourChat] Stopping regular server..." << std::endl; + _stop = true; + + // Stop all rooms + for (auto& room : _rooms) { + room->setStop(); + } + + std::cout << "[YourChat] Regular server stopped." << std::endl; + } + void Server::run() { if (listen(_socket, 5) < 0) { std::cout << "listen not possible" << std::endl; exit(-1); } timeval origTv; - origTv.tv_sec = 5; + origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown origTv.tv_usec = 0; int _maxSd = _socket; std::set activeSockets; @@ -90,7 +112,8 @@ namespace Yc { } } - if (select(_maxSd + 1, &fd, NULL, NULL, &tv) > 0) { + int selectResult = select(_maxSd + 1, &fd, NULL, NULL, &tv); + if (selectResult > 0) { // Neue Verbindung? if (FD_ISSET(_socket, &fd)) { std::thread(&Server::handleRequest, this).detach(); @@ -110,6 +133,13 @@ namespace Yc { } } } + } else if (selectResult < 0) { + if (errno == EINTR) { + // Interrupted by signal, check if we should stop + continue; + } + std::cerr << "[YourChat] select() error: " << strerror(errno) << std::endl; + break; } // AufgerÀumte Sockets entfernen @@ -125,6 +155,7 @@ namespace Yc { } } } + std::cout << "[YourChat] Server run loop exiting" << std::endl; } std::vector Server::roomList() { diff --git a/src/core/server.h b/src/core/server.h index 940837e..89a1618 100755 --- a/src/core/server.h +++ b/src/core/server.h @@ -15,7 +15,9 @@ namespace Yc { { public: Server(std::shared_ptr config, std::shared_ptr database); + ~Server(); void run(); + void stop(); std::vector roomList(); Json::Value jsonRoomList(); bool roomAllowed(std::string roomName, std::string userName, std::string password); diff --git a/src/core/ssl_server.cpp b/src/core/ssl_server.cpp index 212881f..6147fa8 100644 --- a/src/core/ssl_server.cpp +++ b/src/core/ssl_server.cpp @@ -52,14 +52,35 @@ void SSLServer::run() { } void SSLServer::stop() { + std::cout << "[YourChat] Stopping SSL Server..." << std::endl; _running = false; - if (_context) lws_cancel_service(_context); - if (_serverThread.joinable()) _serverThread.join(); - if (_messageThread.joinable()) _messageThread.join(); + + // Wake up the message queue thread + _queueCV.notify_all(); + + // Cancel libwebsockets service + if (_context) { + lws_cancel_service(_context); + } + + // Wait for threads to finish + if (_serverThread.joinable()) { + std::cout << "[YourChat] Waiting for server thread to finish..." << std::endl; + _serverThread.join(); + } + + if (_messageThread.joinable()) { + std::cout << "[YourChat] Waiting for message thread to finish..." << std::endl; + _messageThread.join(); + } + + // Clean up libwebsockets context if (_context) { lws_context_destroy(_context); _context = nullptr; } + + std::cout << "[YourChat] SSL Server stopped." << std::endl; } void SSLServer::startServer() { @@ -88,8 +109,15 @@ void SSLServer::startServer() { } while (_running) { - lws_service(_context, 50); + // Use a shorter timeout to be more responsive to shutdown + int ret = lws_service(_context, 10); + if (ret < 0) { + std::cerr << "[YourChat] lws_service returned error: " << ret << std::endl; + break; + } } + + std::cout << "[YourChat] SSL Server thread exiting" << std::endl; } void SSLServer::processMessageQueue() { @@ -97,7 +125,7 @@ void SSLServer::processMessageQueue() { std::unique_lock lock(_queueMutex); _queueCV.wait(lock, [this](){ return !_messageQueue.empty() || !_running; }); - while (!_messageQueue.empty()) { + while (!_messageQueue.empty() && _running) { std::string msg = std::move(_messageQueue.front()); _messageQueue.pop(); lock.unlock(); @@ -106,6 +134,7 @@ void SSLServer::processMessageQueue() { lock.lock(); } } + std::cout << "[YourChat] Message queue thread exiting" << std::endl; } int SSLServer::wsCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { diff --git a/src/main.cpp b/src/main.cpp index fde0be5..2f11fb2 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,25 +4,64 @@ #include "core/ssl_server.h" #include "lib/database.h" #include +#include +#include +#include +#include + +// Global flag for graceful shutdown +std::atomic g_running{true}; +std::shared_ptr g_sslServer = nullptr; +std::shared_ptr g_server = nullptr; + +// Signal handler for graceful shutdown +void signalHandler(int signal) { + std::cout << "\n[YourChat] Received signal " << signal << ", shutting down gracefully..." << std::endl; + g_running = false; + + if (g_sslServer) { + g_sslServer->stop(); + } + if (g_server) { + g_server->stop(); + } +} // main function int main(int, char **) { + // Set up signal handlers + std::signal(SIGINT, signalHandler); + std::signal(SIGTERM, signalHandler); + auto config = std::make_shared(); auto database = std::make_shared(config); // Check if SSL is enabled bool sslEnabled = config->value("server", "ssl_enabled").asBool(); - if (sslEnabled) { - std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl; - auto sslServer = std::make_shared(config, database); - sslServer->createRooms(); - sslServer->run(); - } else { - std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl; - auto server = std::make_shared(config, database); - server->createRooms(config->group("rooms")); - server->run(); + try { + if (sslEnabled) { + std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl; + g_sslServer = std::make_shared(config, database); + g_sslServer->createRooms(); + g_sslServer->run(); + } else { + std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl; + g_server = std::make_shared(config, database); + g_server->createRooms(config->group("rooms")); + g_server->run(); + } + + // Main loop - wait for shutdown signal + while (g_running) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + std::cout << "[YourChat] Shutdown complete." << std::endl; + + } catch (const std::exception& e) { + std::cerr << "[YourChat] Error: " << e.what() << std::endl; + return 1; } return 0;