diff --git a/src/core/chat_room.cpp b/src/core/chat_room.cpp index 3115432..42c9829 100755 --- a/src/core/chat_room.cpp +++ b/src/core/chat_room.cpp @@ -37,7 +37,31 @@ namespace Yc thread = std::make_unique(&ChatRoom::run, this); } - ChatRoom::~ChatRoom() = default; + ChatRoom::~ChatRoom() { + setStop(); + + // Stop all users first + for (auto& user : _users) { + if (user) { + user->stop(); + } + } + + // Wait for all user threads to finish + for (auto& user : _users) { + if (user && user->thread.joinable()) { + user->thread.join(); + } + } + + // Clear users list + _users.clear(); + + // Now stop and join the room thread + if (thread && thread->joinable()) { + thread->join(); + } + } void ChatRoom::run() { diff --git a/src/core/chat_user.h b/src/core/chat_user.h index 7d3d199..b7b816d 100644 --- a/src/core/chat_user.h +++ b/src/core/chat_user.h @@ -48,6 +48,9 @@ namespace Yc std::string color() const; void setParent(std::shared_ptr parent); + public: + std::thread thread; + private: std::shared_ptr _parent; Yc::Object::User _user; @@ -56,7 +59,6 @@ namespace Yc int _socket; std::string _token; bool _stop; - std::thread thread; void send(std::string out); void send(Json::Value out); diff --git a/src/core/server.cpp b/src/core/server.cpp index c8ed18c..07f0b43 100755 --- a/src/core/server.cpp +++ b/src/core/server.cpp @@ -22,7 +22,8 @@ namespace Yc { Server::Server(std::shared_ptr config, std::shared_ptr database) : _config(std::move(config)), _database(std::move(database)), - _stop(false) { + _stop(false), + _socket(-1) { int port = 1235; try { Json::Value p = _config->value("server", "port"); @@ -43,24 +44,39 @@ namespace Yc { // Fallback to IPv4 close(_socket); _socket = socket(AF_INET, SOCK_STREAM, 0); + if (_socket < 0) { + std::cout << "socket create failed" << std::endl; + exit(-1); + } setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)); struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port); if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) { - std::cout << "bind not possible" << std::endl; exit(-1); + std::cout << "bind not possible on IPv4" << std::endl; + close(_socket); + _socket = -1; + exit(-1); } std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl; } } else { // Fallback to IPv4 directly _socket = socket(AF_INET, SOCK_STREAM, 0); - if (_socket < 0) { std::cout << "socket create failed" << std::endl; exit(-1);} + if (_socket < 0) { + std::cout << "socket create failed" << std::endl; + exit(-1); + } setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); int flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); int ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)); struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port); - if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) { std::cout << "bind not possible" << std::endl; exit(-1);} + if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) { + std::cout << "bind not possible on IPv4" << std::endl; + close(_socket); + _socket = -1; + exit(-1); + } std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl; } } @@ -74,21 +90,35 @@ namespace Yc { } void Server::stop() { + if (_stop) { + return; // Already stopped + } + std::cout << "[YourChat] Stopping regular server..." << std::endl; _stop = true; // Stop all rooms for (auto& room : _rooms) { - room->setStop(); + if (room) { + room->setStop(); + } } + // Clear rooms list to ensure proper cleanup order + _rooms.clear(); + std::cout << "[YourChat] Regular server stopped." << std::endl; } void Server::run() { + if (_socket < 0) { + std::cout << "Invalid socket, cannot start server" << std::endl; + return; + } + if (listen(_socket, 5) < 0) { - std::cout << "listen not possible" << std::endl; - exit(-1); + std::cout << "listen not possible: " << strerror(errno) << std::endl; + return; } timeval origTv; origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown diff --git a/src/core/ssl_server.cpp b/src/core/ssl_server.cpp index 6147fa8..cd89d31 100644 --- a/src/core/ssl_server.cpp +++ b/src/core/ssl_server.cpp @@ -52,6 +52,10 @@ void SSLServer::run() { } void SSLServer::stop() { + if (!_running) { + return; // Already stopped + } + std::cout << "[YourChat] Stopping SSL Server..." << std::endl; _running = false; diff --git a/src/main.cpp b/src/main.cpp index 2f11fb2..479b6c6 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,6 +57,16 @@ int main(int, char **) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } + // Clean up servers before exit + if (g_sslServer) { + g_sslServer->stop(); + g_sslServer.reset(); + } + if (g_server) { + g_server->stop(); + g_server.reset(); + } + std::cout << "[YourChat] Shutdown complete." << std::endl; } catch (const std::exception& e) {